# Emitir una nota de crédito por API: POST /bill/receipts/credit-note/

Revierte total o parcialmente el importe de un comprobante autorizado. Elegís cómo acreditar: por renglón, por monto, por porcentaje o, si no indicás nada, por el cien por ciento del comprobante original. Los ejemplos de esta página se capturaron en sandbox (token yf_test_): el CAE y el número son simulados, ARCA no los emitió y no valen como comprobante fiscal; lo reconocés por simulated: true y livemode: false.

- Método y ruta: `POST /bill/receipts/credit-note/`
- Scope: `invoices:write`
- Recurso: Notas de crédito y débito
- Reintentos seguros: header `Idempotency-Key`

## Qué hace

Revierte total o parcialmente el importe de un comprobante autorizado: por renglón (`lineas`), por monto (`importe_a_acreditar`), por porcentaje (`porcentaje_aplicar`) o, sin ninguno, el 100%. Con un token `yf_test_*` (sandbox) este endpoint no llama a AFIP: persiste un comprobante simulado (`simulated: true`, `livemode: false`, un CAE sintético) en la base sandbox aislada del tenant. Requiere scope `invoices:write`. En un tenant que factura con SIFEN (Paraguay) responde 409 con `error_code: use_sifen_routes`: emití con `POST /sales/` y las notas con `POST /sales/{sale_id}/credit_note/`. Notas de crédito y débito sobre comprobantes de un CUIT dado de baja: se permiten mientras ese CUIT no lo haya registrado otra cuenta; si lo registró otra responde 409 `API_PARTNER_NOTE_ISSUER_CLAIMED_ELSEWHERE`, y si ARCA ya no lista la delegación la nota queda pendiente con `API_PARTNER_NOTE_ISSUER_DELEGATION_MISSING`.

## Parámetros

| Parámetro | Dónde | Requerido | Tipo | Descripción |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | no | string | Clave elegida por el cliente (hasta 255 caracteres) para hacer este POST seguro de reintentar. Un segundo request con la MISMA clave y el MISMO body reproduce la respuesta original (200/201, header `Idempotency-Replayed: true`) en vez de crear un segundo recurso. La misma clave con un body DISTINTO devuelve 422. La clave está scopeada al token exacto (yf_live_*/yf_test_*) que la usó — dos tokens nunca colisionan aunque manden la misma clave. TTL: 24 horas. |

## Cuerpo del request (application/json)

| Campo | Tipo | Requerido | Descripción |
| --- | --- | --- | --- |
| `comprobante_asociado_id` | string | sí | Id del comprobante (factura) aprobado que esta nota acredita. |
| `motivo` | string | no |  |
| `lineas` | array de object | no | Devolución por renglón. |
| `lineas[].linea` | integer | sí | Índice (desde 0) del renglón del comprobante original. |
| `lineas[].cantidad` | number | sí | Unidades que se devuelven (no puede superar la cantidad original). |
| `importe_a_acreditar` | number | no | Monto a acreditar, IVA incluido (no puede superar el total del comprobante). |
| `porcentaje_aplicar` | number | no | Porcentaje del comprobante a acreditar. |
| `items` | array de object | no | Ya no se usa para devoluciones parciales: usá `lineas`, `importe_a_acreditar` o `porcentaje_aplicar`. |
| `importe_total` | number | no |  |
| `ambiente` | string | no | Ignorado: el ambiente sale de la configuración de la cuenta. Valores: production, testing. Por defecto: production. |
| `autorizar` | boolean | no | Por defecto: false. |

## Respuesta 200

| Campo | Tipo | Requerido | Descripción |
| --- | --- | --- | --- |
| `success` | boolean | no |  |
| `data` | object | no |  |
| `data.id` | string | no |  |
| `data.tipo_comprobante` | integer | no |  |
| `data.punto_venta` | integer | no |  |
| `data.numero_comprobante` | integer | no |  |
| `data.cae` | string | no | Código de Autorización Electrónico de AFIP (o sintético en sandbox). |
| `data.cae_vencimiento` | string | no |  |
| `data.fecha_comprobante` | string | no |  |
| `data.estado` | string | no |  |
| `data.ambiente` | string | no |  |
| `data.livemode` | boolean | no | false cuando el comprobante fue emitido por un token yf_test_* (simulado, sin AFIP real). |
| `data.simulated` | boolean | no | true en modo sandbox: el CAE tiene el formato correcto pero NO es válido para un comprobante fiscal real. |
| `data.iva_handling` | object | no |  |
| `data.iva_handling.incluye_iva_discriminado` | boolean | no |  |
| `data.iva_handling.tipo_comprobante_nombre` | string | no |  |
| `data.iva_handling.condicion_fiscal_emisor` | string | no |  |
| `data.idempotent_replay` | boolean | no | true si esta respuesta es la reproducción de un request anterior idéntico. |
| `data.items` | array de object | no |  |
| `data.items[].Descripcion` | string | no |  |
| `data.items[].Cantidad` | number | no |  |
| `data.items[].Precio` | number | no | Precio unitario (neto de IVA cuando el tipo discrimina IVA). |
| `data.items[].Bonificacion` | number | no |  |
| `data.items[].IvaId` | integer | no | Alícuota AFIP (3=0%, 4=10.5%, 5=21%, 6=27%, 8=5%, 9=2.5%). |
| `data.items[].importe_neto_linea` | number | no | Neto de la línea: Precio x Cantidad - Bonificacion, redondeado a 2 decimales (ROUND_HALF_UP). Calculado por el backend. |
| `data.items[].importe_iva_linea` | number | no | IVA de la línea (0 si el tipo no discrimina IVA, 0% o exento). Calculado por el backend. |
| `data.items[].importe_total_linea` | number | no | importe_neto_linea + importe_iva_linea. La suma de las líneas puede diferir de importe_total por el redondeo por línea y no incluye tributos. |
| `message` | string | no |  |
| `_links` | object | no | Mapa HATEOAS: cada valor es un link accionable relativo a este recurso. |

## Ejemplo capturado

Capturado el 2026-11-10 en el entorno de pruebas con un token `yf_test_*`.

Request:

```json
{
  "comprobante_asociado_id": "6af28fe59d98ce51ca3bc5c7",
  "motivo": "Devolucion de mercaderia",
  "lineas": [
    {
      "linea": 1,
      "cantidad": 1
    }
  ],
  "autorizar": true
}
```

Respuesta (HTTP 200):

```json
{
  "success": true,
  "data": {
    "motivo": "Devolucion de mercaderia",
    "lineas": [
      {
        "linea": 1,
        "cantidad": 1
      }
    ],
    "tipo_comprobante": 8,
    "punto_venta": 1,
    "numero_comprobante": 4261715,
    "cae": "05561320376600",
    "cae_vencimiento": "20261120",
    "fecha_comprobante": "20261110",
    "comprobante_asociado_id": "6af28fe59d98ce51ca3bc5c7",
    "estado": "autorizado",
    "ambiente": "sandbox",
    "livemode": false,
    "simulated": true,
    "simulated_note": "Sandbox test-mode document: no ARCA call was made. This CAE is synthetic and is not valid for a real fiscal document. For a real homologation CAE use a live token with \"ambiente\": \"testing\".",
    "created_at": "2026-11-10T03:30:46.939211+00:00",
    "email": "demo@example.com",
    "id": "6af28fe69d98ce51ca3bc5cd",
    "sandbox": true
  },
  "message": "Simulated credit note created in sandbox mode (no real ARCA CAE)"
}
```

## Errores

| Estado | Descripción | Código |
| --- | --- | --- |
| 400 | Solicitud inválida (body ausente o con formato incorrecto). | `VALIDATION_ERROR` |
| 401 | Falta autenticación o el token es inválido/expiró. | `UNAUTHORIZED` |
| 403 | El token no tiene el/los scope(s) requeridos, o el plan del tenant no habilita el módulo. | `FORBIDDEN` |
| 409 | Conflicto de estado (p. ej. editar un recurso en un estado que no lo permite). | `CONFLICT` |
| 422 | Semánticamente inválido — incluye la reutilización de un Idempotency-Key con un body distinto. | `UNPROCESSABLE_ENTITY` |
| 429 | Se superó el rate limit del endpoint o del tenant. Ver headers `X-RateLimit-*` y `Retry-After`. | `RATE_LIMITED` |

## Código: curl

```
curl -sS -X POST "https://api.yo-facturo.com/api/v1/bill/receipts/credit-note/" \
  -H "X-API-Key: $YF_TEST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "comprobante_asociado_id": "6af28fe59d98ce51ca3bc5c7",
  "motivo": "Devolucion de mercaderia",
  "lineas": [
    {
      "linea": 1,
      "cantidad": 1
    }
  ],
  "autorizar": true
}'
```

## Relacionado

- [Emitir factura](https://yo-facturo.com/dev/referencia/comprobantes/emitir-factura/)

Referencia completa: https://yo-facturo.com/dev/referencia/
