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

# Crear factura electrónica

> Crea una factura electrónica y, según la política, la timbra ante la DIAN.

Es [el mismo endpoint de crear factura](/client/invoices/create). Mandar `items` es lo que hace que OnePay emita el documento ante la DIAN en vez de registrar uno externo; en ese caso `provider`, `provider_id` y `amount` los pone el sistema.

Responde `201` sin esperar a la DIAN. El resultado del timbrado llega por el webhook `invoice.stamped` o `invoice.stamp_rejected`.

### Headers

<ParamField header="x-idempotency" type="string" required placeholder="Token único para garantizar la idempotencia de la petición">
  Token único para garantizar la idempotencia de la petición
</ParamField>

<Warning>
  Sin `Idempotency-Key`, un reintento por timeout de red crea dos facturas: dos documentos ante la DIAN, IVA declarado dos veces y una nota crédito para arreglarlo.
</Warning>

### Body

<ParamField body="customer_id" type="string" required placeholder="cus_01J8XK2P9WQZ">
  Cliente al que se le factura. Debe tener completos los datos que exige la DIAN — ver [datos del receptor](/client/electronic-invoices/index#datos-que-exige-el-receptor). Si falta alguno, la respuesta es `422` con todos los campos faltantes.
</ParamField>

<ParamField body="items" type="array" required>
  Líneas de la factura. Mínimo 1, máximo 200. Cada línea puede venir del catálogo (`price_id`) o definirse suelta.

  <Expandable title="Campos de la línea">
    <ParamField body="price_id" type="string" placeholder="price_01J8XK7T2M">
      Precio del catálogo. OnePay resuelve descripción, monto e impuesto. Requerido si no mandas `description` y `unit_amount`.
    </ParamField>

    <ParamField body="description" type="string" placeholder="Plan Fibra 200 Mbps">
      Descripción de la línea, hasta 500 caracteres. Sobreescribe el nombre del precio si mandas ambos.
    </ParamField>

    <ParamField body="quantity" type="number" placeholder="1">
      Cantidad. Admite decimales (por ejemplo `1.5` horas). Por defecto `1`, máximo `100000`.
    </ParamField>

    <ParamField body="unit_amount" type="integer" placeholder="8990000">
      Valor unitario **en centavos**. `8990000` son $89.900 COP. Máximo `10000000000` ($100.000.000).
    </ParamField>

    <ParamField body="tax.rate" type="number" placeholder="19">
      Tarifa del impuesto en porcentaje. `0` es una línea exenta o excluida. Si la omites, se hereda del precio y luego del producto.
    </ParamField>

    <ParamField body="tax.type" type="string" placeholder="IVA">
      Tipo de impuesto. Por defecto `IVA`.
    </ParamField>

    <ParamField body="tax.behavior" type="string" placeholder="exclusive">
      `exclusive` (por defecto) suma el impuesto sobre `unit_amount`. `inclusive` significa que `unit_amount` ya lo trae y OnePay lo desagrega.
    </ParamField>

    <ParamField body="unit_measure" type="string" placeholder="94">
      Código de unidad de medida (UNECE Rec 20) que exige el XML. Por defecto `94` (unidad).
    </ParamField>

    <ParamField body="product_code" type="string" placeholder="4901">
      Código del producto según el estándar que uses.
    </ParamField>

    <ParamField body="product_code_standard" type="string" placeholder="999">
      Estándar del código: `999` (interno), `UNSPSC`, `GTIN`.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="stamp_policy" type="string" placeholder="on_payment">
  Si se emite ante la DIAN y cuándo:

  * `none` **(por defecto)** — no se emite. La factura se crea y se cobra igual, sin documento fiscal y sin exigir los datos fiscales del cliente.
  * `on_payment` — al aprobarse el pago.
  * `on_issue` — al crear la factura, antes de cobrar.
  * `manual` — cuando llames a `/stamp`.

  Ver [cuándo se timbra](/client/electronic-invoices/index#cuando-se-timbra) antes de elegir `on_issue`.
</ParamField>

<ParamField body="name" type="string" placeholder="Plan Fibra 200 Mbps - agosto 2026">
  Título del cobro que ve el cliente. Hasta 100 caracteres.
</ParamField>

<ParamField body="description" type="string">
  Descripción detallada. Hasta 2000 caracteres.
</ParamField>

<ParamField body="reference" type="string" placeholder="1020304050">
  Referencia con la que el cliente consulta su deuda en el portal de pagos. Se recomienda el documento del titular.
</ParamField>

<ParamField body="due_date" type="date" placeholder="2026-08-16">
  Fecha de pago oportuno.
</ParamField>

<ParamField body="currency" type="string" placeholder="COP">
  Moneda. Por defecto la de tu empresa.
</ParamField>

<ParamField body="metadata" type="object" placeholder="{}">
  Datos adicionales que quieras persistir en la factura.
</ParamField>

<Warning>
  **El total de la factura tiene que ser cobrable.** La suma de las líneas debe quedar entre `10000` ($100) y `10000000000` ($100.000.000), el mismo rango que acepta el flujo sin `items`.

  Fuera de ahí la respuesta es `422` con `invalid_invoice_line`. El caso que más sorprende es el total en cero: una factura gratis generaría un cobro que nadie puede pagar.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://api.onepay.la/v1/invoices \
    -H "Authorization: Bearer $ONEPAY_API_KEY" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: 8f14e45f-ea6c-4b3d-9c1a-2b7d3e5f9a01" \
    -d '{
      "customer_id": "cus_01J8XK2P9WQZ",
      "name": "Plan Fibra 200 Mbps - agosto 2026",
      "stamp_policy": "on_payment",
      "due_date": "2026-08-16",
      "items": [
        { "description": "Plan Fibra 200 Mbps", "unit_amount": 8990000, "tax": { "rate": 19 } },
        { "price_id": "price_01J8XK7T2M", "quantity": 1 }
      ]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 201 theme={null}
  {
    "id": "inv_01J8XK9V4N",
    "status": "CREATED",
    "fiscal_status": null,
    "stamp_policy": "on_payment",
    "currency": "COP",
    "due_date": "2026-08-16",
    "customer": {
      "id": "cus_01J8XK2P9WQZ",
      "name": "Ana Ramírez",
      "email": "ana@ejemplo.com",
      "document_type": "CC",
      "document_number": "1020304050"
    },
    "items": [
      {
        "description": "Plan Fibra 200 Mbps",
        "quantity": 1,
        "unit_amount": 8990000,
        "subtotal": 8990000,
        "tax_type": "IVA",
        "tax_rate": 19,
        "tax_amount": 1708100,
        "total": 10698100,
        "unit_measure": "94",
        "price_id": null
      }
    ],
    "totals": { "subtotal": 8990000, "tax_amount": 1708100, "total": 10698100 },
    "amount": 106981,
    "payment_id": "pay_01J8XKC5D2",
    "stampings": [],
    "created_at": "2026-08-01T14:22:10+00:00"
  }
  ```

  ```json 422 theme={null}
  {
    "code": "customer_not_invoiceable",
    "message": "No se puede facturar: al cliente le faltan datos que exige la DIAN (dirección).",
    "errors": {
      "customer.address": ["required"]
    }
  }
  ```

  ```json 422 theme={null}
  {
    "code": "invalid_invoice_line",
    "message": "El total de la factura (0 centavos) está fuera del rango cobrable (10000 a 10000000000 centavos)."
  }
  ```
</ResponseExample>
