> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usecroma.com/llms.txt
> Use this file to discover all available pages before exploring further.

# DIAN Electronic Invoicing

> Read a company's or person's electronic invoicing at Colombia's DIAN: the documents it issued and received, each document in full, DIAN's monthly report and the account's profile.

DIAN (Dirección de Impuestos y Aduanas Nacionales) is Colombia's tax authority, and
every electronic invoice, credit and debit note, support document, payroll document
and event passes through its electronic-invoicing system. An account there holds
everything the company or person issued and received. These endpoints read that
account as the taxpayer's own connection.

## Connect your account

DIAN's electronic-invoicing system has no password: access is a link DIAN emails to the address registered in the RUT of the person who asks for it (for a company, its legal representative). Ask for it with the access requests endpoint below, or in DIAN's electronic-invoicing system, then register the link here within the 60 minutes DIAN accepts it. DIAN keeps that access open for about an hour, so register the link when you are about to query and run what you need in that window. After it, queries answer `422 connection_rejected`: ask for a new link and register it again, and the same connection is renewed, keeping its id.

`POST /co/dian-facturacion/connections/v1` Register a connection once. Croma checks it with the source before saving it, and answers with its id and a masked name.

| Field | Type | Notes |
| - | - | - |
| `access_link` | string | **Required.** The whole link from DIAN's email, as it arrived. DIAN accepts it for 60 minutes. |
| `authorized` | boolean | **Required.** `true`: you confirm you are the account's owner or have the owner's authorization to use it. |

```bash theme={"dark"}
curl https://api.croma.run/co/dian-facturacion/connections/v1 \
  -H "Authorization: Bearer $CROMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "access_link": "<access link from the DIAN email>",
        "authorized": true
      }'
```

```json theme={"dark"}
{
  "data": {
    "id": "conn_2f8Kq1xVb7Lm0Pz9Rt4Wc3",
    "source": "dian-facturacion",
    "status": "active",
    "display_name": "J*** P*** G***",
    "usage": {
      "sign_ins_today": 1,
      "daily_limit": null,
      "resets_at": "2026-10-01T05:00:00.000Z"
    },
    "available_again_at": null,
    "created_at": "2026-09-30T20:00:00.000Z",
    "last_used_at": "2026-09-30T20:00:00.000Z"
  }
}
```

Every query then runs as one of your organization's connections. Croma picks one, keeps its session open between queries, and moves to the next when one reaches its daily allowance. Register more than one to get more capacity a day. To run as a specific one, send its id as `connection_id`.

Registering an account that is already connected renews it: the connection takes the new values, keeps its id and answers `200`, so nothing that stores the id has to change.

How the flow works, step by step: [Connections](/connections).

List and delete them:

```bash theme={"dark"}
curl https://api.croma.run/co/dian-facturacion/connections/v1 -H "Authorization: Bearer $CROMA_API_KEY"
curl -X DELETE https://api.croma.run/co/dian-facturacion/connections/v1/conn_2f8Kq1xVb7Lm0Pz9Rt4Wc3 -H "Authorization: Bearer $CROMA_API_KEY"
```

Over [MCP](/mcp-server), the same verbs are the `dian_facturacion_connect`, `dian_facturacion_list_connections`, `dian_facturacion_delete_connection` tools. Connecting from an agent never passes the credentials through the conversation: the agent gets a secure link, and the user enters the account's details in the [Croma console](https://platform.usecroma.com/connections).

When a query cannot run as any connection:

| Status | Code | Meaning |
| - | - | - |
| 409 | `connection_required` | The organization has no connection for this source yet. |
| 422 | `connection_rejected` | The source no longer accepts the connection's credentials. |
| 429 | `connections_exhausted` | Every connection used its daily allowance. `Retry-After` says when one is available again. |
| 422 | `connection_limit_reached` | The organization already has 5 connections for this source (on register). |

> [!NOTE]
>
> Credentials are encrypted as soon as they reach Croma, bound to your organization, and can only be opened by the isolated service that signs in to the source on your behalf. They are never returned by the API or shown to anyone. Deleting a connection destroys it permanently.

## Access requests

`POST /co/dian-facturacion/access-requests/v1` [Live](/live-lookups)

Have DIAN send the access link a connection is registered with, without leaving your product: the person (or the company's legal representative) receives it at the email in their RUT.

| Field | Type | Notes |
| - | - | - |
| `document_type` | enum | The document type of the person the access is for: `CC`, `CE`, `TI`, `RC`, `PA` or `NIT`. Default `CC`. |
| `document_number` | string | **Required.** The document number of the person the access is for (the legal representative's, for a company), without dots or commas. DIAN sends the link to the email registered in that person's RUT. |
| `company_nit` | string | Optional. The NIT of the company the access is for, without the verification digit, dots or dashes; `document_number` is then its legal representative's. Empty asks for the person's own access. |

```bash theme={"dark"}
curl https://api.croma.run/co/dian-facturacion/access-requests/v1 \
  -H "Authorization: Bearer $CROMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "document_type": "CC",
        "document_number": "1234567890",
        "company_nit": "900123456"
      }'
```

## Response

`sent` is `true` when DIAN accepted the request and emailed the link to the address in the person's RUT; `message` is DIAN's own answer. The link works for `expires_in_minutes` (60). Register it as a connection within that time.

> [!NOTE]
>
> This call runs without a connection: it is how one starts. It is billed like any other call.

## Issued documents

`POST /co/dian-facturacion/issued-documents/v1` [Live](/live-lookups)

| Field | Type | Notes |
| - | - | - |
| `from_date` | string | **Required.** First issue date to include, `yyyy-mm-dd`. |
| `to_date` | string | **Required.** Last issue date to include, `yyyy-mm-dd`, at most a year after `from_date`. For a longer period, call once per year. |
| `connection_id` | string | The connection to run as. Each connection reads its own account's documents, so with more than one in your organization it is required; without it the call answers `409 connection_id_required`. |

```bash theme={"dark"}
curl https://api.croma.run/co/dian-facturacion/issued-documents/v1 \
  -H "Authorization: Bearer $CROMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "from_date": "2026-01-01", "to_date": "2026-06-30" }'
```

## Response

| Field | Notes |
| - | - |
| `from_date`, `to_date` | Echo the range. |
| `taxpayer` | The account's `nit` and `name`. |
| `count` | Number of documents returned. |
| `by_type[]` | Count and summed `total` per document type. |
| `documents[]` | One per electronic document (below). |

Each document has its `cufe` (the key), `document_type_code` and `document_type`, `series` and `number`, `issued_on` and `received_at`, the `issuer` and `recipient` (`nit`, `name`), `currency`, `payment_form` and `payment_method` (DIAN's codes), every tax DIAN totals in `taxes` and the `withholdings` (ReteIVA, ReteRenta, ReteICA), the `total`, DIAN's validation `status` and its `radian_status` as a título valor. Besides invoices, the lists carry credit and debit notes, support documents, payroll and the events (application responses) the account issued or received.

```json theme={"dark"}
{
  "data": {
    "from_date": "2026-01-01",
    "to_date": "2026-06-30",
    "taxpayer": { "nit": "900123456", "name": "EJEMPLO S.A.S" },
    "count": 1,
    "by_type": [{ "document_type": "Factura electrónica", "count": 1, "total": 1190000 }],
    "documents": [
      {
        "cufe": "a1b2c3d4e5f60718...",
        "document_type_code": "01",
        "document_type": "Factura electrónica",
        "series": "FE",
        "number": "27",
        "issued_on": "2026-03-09",
        "received_at": "2026-03-09T09:45:16-05:00",
        "issuer": { "nit": "900123456", "name": "EJEMPLO S.A.S" },
        "recipient": { "nit": "860000001", "name": "CLIENTE S.A.S" },
        "currency": "COP",
        "payment_form": "2",
        "payment_method": "42",
        "taxes": { "iva": 190000, "ica": 0, "ic": 0, "inc": 0, "timbre": 0, "inc_bolsas": 0, "in_carbono": 0, "in_combustibles": 0, "ic_datos": 0, "icl": 0, "inpp": 0, "ibua": 0, "icui": 0 },
        "withholdings": { "rete_iva": 0, "rete_renta": 0, "rete_ica": 0 },
        "total": 1190000,
        "status": "Aprobado con notificación",
        "radian_status": "Factura Electrónica"
      }
    ]
  }
}
```

> [!NOTE]
>
> Every call reads DIAN live as your connection, so the answer is current and
> is never shared between organizations.

> [!NOTE]
>
> This lookup can take longer than a typical request. It is an
> [async job](/async-jobs). By default the request waits inline and returns
> `{ data }`, or you can poll / use a `callback_url`.

## Received documents

`POST /co/dian-facturacion/received-documents/v1` [Live](/live-lookups)

Same shape as the issued documents.

| Field | Type | Notes |
| - | - | - |
| `from_date` | string | **Required.** First issue date to include, `yyyy-mm-dd`. |
| `to_date` | string | **Required.** Last issue date to include, `yyyy-mm-dd`, at most a year after `from_date`. For a longer period, call once per year. |
| `connection_id` | string | The connection to run as. Each connection reads its own account's documents, so with more than one in your organization it is required; without it the call answers `409 connection_id_required`. |

```bash theme={"dark"}
curl https://api.croma.run/co/dian-facturacion/received-documents/v1 \
  -H "Authorization: Bearer $CROMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "from_date": "2026-01-01", "to_date": "2026-06-30" }'
```

> [!NOTE]
>
> Every call reads DIAN live as your connection, so the answer is current and
> is never shared between organizations.

> [!NOTE]
>
> This lookup can take longer than a typical request. It is an
> [async job](/async-jobs). By default the request waits inline and returns
> `{ data }`, or you can poll / use a `callback_url`.

## One document

`POST /co/dian-facturacion/document/v1` [Live](/live-lookups)

| Field | Type | Notes |
| - | - | - |
| `cufe` | string | **Required.** CUFE/CUDE (unique electronic-document code) or UUID of the document. |
| `issued_on` | string | **Required.** The document's issue date, `yyyy-mm-dd`, as the issued or received documents list it (`issued_on`). |
| `connection_id` | string | The connection to run as. Each connection reads its own account's documents, so with more than one in your organization it is required; without it the call answers `409 connection_id_required`. |

```bash theme={"dark"}
curl https://api.croma.run/co/dian-facturacion/document/v1 \
  -H "Authorization: Bearer $CROMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "cufe": "a1b2c3d4e5f60718a1b2c3d4e5f60718a1b2c3d4e5f60718a1b2c3d4e5f60718a1b2c3d4e5f60718a1b2c3d4e5f60718",
        "issued_on": "2026-03-09"
      }'
```

## Response

`found` says whether the account has the document on that date; when `false` the rest is empty. Otherwise you get the document's header (`document_type`, `series`, `number`, `issued_on`, `issued_at`, `due_on`, `issuer`, `recipient`, `currency`, `payment_form`, `payment_method`, `notes`), its `lines` (`description`, `quantity`, `unit`, `unit_price`, `line_total` and each line's `taxes`), its own monetary `totals`, the `taxes` and `total` as DIAN's registry shows them, the `legitimate_holder`, DIAN's `validations`, its `events` (acuse de recibo, recibo del bien, aceptación, endoso...), and the original files: `xml` (UBL 2.1) and `pdf_base64`. Payroll, support documents and events carry no lines or files here; their header, validations and events still come back.

> [!NOTE]
>
> Take `cufe` and `issued_on` from a row of the issued or received documents.

> [!NOTE]
>
> This lookup can take longer than a typical request. It is an
> [async job](/async-jobs). By default the request waits inline and returns
> `{ data }`, or you can poll / use a `callback_url`.

## Monthly report

`POST /co/dian-facturacion/monthly-reports/v1` [Live](/live-lookups)

DIAN issues it to accounts that invoice electronically, usually in the first weeks of the next month.

| Field | Type | Notes |
| - | - | - |
| `year` | integer | **Required.** The report's year. |
| `month` | integer | **Required.** The report's month, 1 to 12. |
| `connection_id` | string | The connection to run as. Each connection reads its own account's documents, so with more than one in your organization it is required; without it the call answers `409 connection_id_required`. |

```bash theme={"dark"}
curl https://api.croma.run/co/dian-facturacion/monthly-reports/v1 \
  -H "Authorization: Bearer $CROMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "year": 2025, "month": 12 }'
```

## Response

`available` says whether DIAN issued a report for the month; when `false` the rest is empty. A report has its `reference`, `dated_on`, `cutoff_date` and `replaces_previous`; `documents[]` with, per document type, what was `issued` and `received` (`month_count`, `month_amount`, `year_count`, `year_amount`); and `indicators[]` for the month and the two before it (`count`, `daily_average_count`, `amount`, `daily_average_amount`, issued and received).

> [!NOTE]
>
> This lookup can take longer than a typical request. It is an
> [async job](/async-jobs). By default the request waits inline and returns
> `{ data }`, or you can poll / use a `callback_url`.

## Profile

`POST /co/dian-facturacion/profile/v1` [Live](/live-lookups)

| Field | Type | Notes |
| - | - | - |
| `connection_id` | string | The connection to run as. Each connection reads its own account's documents, so with more than one in your organization it is required; without it the call answers `409 connection_id_required`. |

```bash theme={"dark"}
curl https://api.croma.run/co/dian-facturacion/profile/v1 \
  -H "Authorization: Bearer $CROMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

## Response

The account's `nit`, `name`, `business_name`, `email`, its `status` in DIAN's electronic-invoicing system, the `reception_email` where it receives invoices, its `legal_representatives`, its `operation_modes` (own software, a technology provider's, or DIAN's), and the `numbering_ranges` associated with its software (`prefix`, `resolution`, `from_number`, `to_number`, `associated_on`, `expires_on`).

> [!NOTE]
>
> This lookup can take longer than a typical request. It is an
> [async job](/async-jobs). By default the request waits inline and returns
> `{ data }`, or you can poll / use a `callback_url`.

> **[Full reference](/api-reference/overview)**
>
> Schemas, all response fields, and an interactive playground.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.