{
  "openapi": "3.1.1",
  "info": {
    "title": "Boletura API",
    "description": "API para emitir boletas, facturas y notas de crédito y de débito electrónicas válidas ante SUNAT y entregar su PDF y su XML al instante. La plataforma se encarga del envío, los resúmenes diarios, las bajas y el almacenamiento; la API no pide UBL ni catálogos, salvo la unidad de medida y el código de detracción.\n\nLa API key elige el ambiente: `test` usa SUNAT beta y `live`, SUNAT producción. El envío a SUNAT es asíncrono: el resultado llega a `sunat_status` y por webhook. Fechas `YYYY-MM-DD` de Lima, timestamps RFC 3339 en UTC e importes como números JSON.\n\nEsta referencia no describe los webhooks: sus eventos, su cuerpo y la verificación de la firma están en la guía [Webhooks y sincronización](https://docs.boletura.com/guias/webhooks/) del portal de documentación.",
    "contact": {
      "name": "Soporte de Boletura",
      "email": "soporte@boletura.com"
    },
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://api.boletura.com",
      "description": "Producción: claves `test` y `live`."
    }
  ],
  "paths": {
    "/v1/companies": {
      "get": {
        "tags": [
          "Companies"
        ],
        "summary": "Lista las empresas del tenant con sus series del ambiente de la clave",
        "description": "Permite resolver `company_id` y las series sin entrar al back office. Lista todas las empresas del tenant, aunque la clave tenga una por defecto, ordenadas por creación. No devuelve certificados, credenciales ni otros secretos.\n\nRequiere el scope `companies:read`.",
        "operationId": "ListIntegrationCompanies",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "Tamaño de la página, de 1 a 200; por defecto 50. Fuera de ese rango responde `422 limit_invalid`, y un valor que no es un número, `400 bad_request`.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "El `next_cursor` de la página anterior. Es opaco y vale solo para el orden con el que se generó: otro responde `400 invalid_cursor`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Solicitud correcta.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PageOfIntegrationCompanyDto"
                },
                "examples": {
                  "una_empresa_con_dos_series": {
                    "summary": "Una empresa con dos series",
                    "value": {
                      "data": [
                        {
                          "id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6b",
                          "ruc": "20100066603",
                          "legal_name": "Empresa de Ejemplo S.A.C.",
                          "trade_name": "Ejemplo",
                          "status": "draft",
                          "environments_ready": {
                            "test": true,
                            "live": false
                          },
                          "series": [
                            {
                              "id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6d",
                              "establishment_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6c",
                              "environment": "test",
                              "document_type": "boleta",
                              "code": "B001",
                              "is_default": true
                            },
                            {
                              "id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6e",
                              "establishment_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6c",
                              "environment": "test",
                              "document_type": "factura",
                              "code": "F001",
                              "is_default": true
                            }
                          ]
                        }
                      ],
                      "next_cursor": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Solicitud mal formada. Códigos: `invalid_cursor` y `bad_request`, cuando un parámetro no tiene el formato de su tipo, como `limit=abc`. No se reintenta sin corregirla.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_cursor": {
                    "summary": "invalid_cursor",
                    "value": {
                      "error": {
                        "type": "bad_request",
                        "code": "invalid_cursor",
                        "message": "El cursor no es válido.",
                        "param": "cursor",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope companies:read que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`limit_invalid`: `limit` está fuera del rango de 1 a 200.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "limit_invalid": {
                    "summary": "limit_invalid",
                    "value": {
                      "error": {
                        "type": "validation_error",
                        "code": "limit_invalid",
                        "message": "El límite debe estar entre 1 y 200.",
                        "param": "limit",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable` o `storage_unavailable`. Se reintenta con una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Emite una boleta o una factura",
        "description": "Responde de inmediato con el número, el PDF y el QR; el envío a SUNAT es asíncrono, y su resultado se consulta en `sunat_status` y `sunat.response_code`, nunca como un error HTTP de esta operación. La plataforma recalcula todos los importes. Una solicitud rechazada no consume número.\n\nRequiere el scope `documents:write`.",
        "operationId": "IssueDocument",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Identifica la operación para reintentarla sin duplicarla durante 24 horas desde la respuesta final; se recomienda un UUID. De 1 a 128 caracteres `[A-Za-z0-9._:-]`. Sin ella responde `400 idempotency_key_required`, y con otro formato, `400 idempotency_key_invalid`. La misma clave con otra solicitud responde `422 idempotency_key_reused`, y con la primera aún en curso, `409 idempotency_in_progress`.",
            "required": true,
            "schema": {
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueDocumentCommand"
              },
              "examples": {
                "boleta": {
                  "summary": "Boleta",
                  "value": {
                    "type": "boleta",
                    "external_id": "venta-98231",
                    "customer": {
                      "document_type": "dni",
                      "document_number": "45678912",
                      "name": "Juan Pérez"
                    },
                    "items": [
                      {
                        "description": "Estacionamiento 2 horas",
                        "quantity": 1,
                        "unit": "ZZ",
                        "unit_price": 12.00
                      }
                    ],
                    "metadata": {
                      "placa": "ABC-123"
                    }
                  }
                },
                "factura": {
                  "summary": "Factura",
                  "value": {
                    "type": "factura",
                    "customer": {
                      "document_type": "ruc",
                      "document_number": "20131312955",
                      "name": "Cliente S.A.C."
                    },
                    "items": [
                      {
                        "description": "Servicio mensual",
                        "quantity": 2,
                        "unit": "ZZ",
                        "unit_value": 100.00
                      }
                    ]
                  }
                },
                "factura_con_detracción": {
                  "summary": "Factura con detracción",
                  "description": "La respuesta es igual a la de una factura sin detracción, porque el documento no devuelve ese dato.",
                  "value": {
                    "type": "factura",
                    "customer": {
                      "document_type": "ruc",
                      "document_number": "20131312955",
                      "name": "Cliente S.A.C."
                    },
                    "detraction": {
                      "code": "037"
                    },
                    "items": [
                      {
                        "description": "Servicio de estacionamiento mensual",
                        "quantity": 1,
                        "unit": "ZZ",
                        "unit_value": 1000.00
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Documento emitido y numerado. Con `Idempotent-Replayed: true`, es la respuesta guardada de la solicitud original.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentDto"
                },
                "examples": {
                  "boleta": {
                    "summary": "Boleta",
                    "value": {
                      "id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5a",
                      "object": "document",
                      "environment": "test",
                      "company_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6b",
                      "type": "boleta",
                      "series": "B001",
                      "number": 125,
                      "full_number": "B001-125",
                      "issue_date": "2026-10-09",
                      "currency": "PEN",
                      "customer": {
                        "document_type": "dni",
                        "document_number": "45678912",
                        "name": "Juan Pérez",
                        "address": null,
                        "email": null
                      },
                      "items": [
                        {
                          "line_number": 1,
                          "product_code": null,
                          "description": "Estacionamiento 2 horas",
                          "quantity": 1,
                          "unit": "ZZ",
                          "unit_price": 12,
                          "unit_value": 10.1694915254,
                          "tax_affectation": "gravado",
                          "igv_rate": 18.00,
                          "line_value": 10.17,
                          "igv_amount": 1.83,
                          "line_total": 12.00
                        }
                      ],
                      "totals": {
                        "taxable": 10.17,
                        "exempt": 0.00,
                        "unaffected": 0.00,
                        "discount": 0.00,
                        "igv": 1.83,
                        "total": 12.00,
                        "amount_in_words": "DOCE CON 00/100 SOLES"
                      },
                      "status": "issued",
                      "sunat_status": "pending",
                      "delivery_status": "none",
                      "sunat": {
                        "response_code": null,
                        "description": null,
                        "notes": [ ],
                        "deadline_at": "2026-10-17T04:59:59.000000Z",
                        "submitted_at": null,
                        "accepted_at": null,
                        "reconciliation_required": false
                      },
                      "hash": "2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_text": "20100066603|03|B001|125|1.83|12.00|2026-10-09|1|45678912|2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_image": "data:image/png;base64,iVBORw0KGgo=",
                      "links": {
                        "pdf": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5a/pdf",
                        "xml": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5a/xml",
                        "cdr": null
                      },
                      "affected_document_id": null,
                      "credit_note": null,
                      "debit_note": null,
                      "external_id": "venta-98231",
                      "replaces_document_id": null,
                      "metadata": {
                        "placa": "ABC-123"
                      },
                      "created_at": "2026-10-09T14:03:21.482913Z",
                      "updated_at": "2026-10-09T14:03:21.482913Z"
                    }
                  },
                  "factura": {
                    "summary": "Factura",
                    "value": {
                      "id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5b",
                      "object": "document",
                      "environment": "test",
                      "company_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6b",
                      "type": "factura",
                      "series": "F001",
                      "number": 42,
                      "full_number": "F001-42",
                      "issue_date": "2026-10-09",
                      "currency": "PEN",
                      "customer": {
                        "document_type": "ruc",
                        "document_number": "20131312955",
                        "name": "Cliente S.A.C.",
                        "address": null,
                        "email": null
                      },
                      "items": [
                        {
                          "line_number": 1,
                          "product_code": null,
                          "description": "Servicio mensual",
                          "quantity": 2,
                          "unit": "ZZ",
                          "unit_price": 118,
                          "unit_value": 100,
                          "tax_affectation": "gravado",
                          "igv_rate": 18.00,
                          "line_value": 200.00,
                          "igv_amount": 36.00,
                          "line_total": 236.00
                        }
                      ],
                      "totals": {
                        "taxable": 200.00,
                        "exempt": 0.00,
                        "unaffected": 0.00,
                        "discount": 0.00,
                        "igv": 36.00,
                        "total": 236.00,
                        "amount_in_words": "DOSCIENTOS TREINTA Y SEIS CON 00/100 SOLES"
                      },
                      "status": "issued",
                      "sunat_status": "pending",
                      "delivery_status": "none",
                      "sunat": {
                        "response_code": null,
                        "description": null,
                        "notes": [ ],
                        "deadline_at": "2026-10-13T04:59:59.000000Z",
                        "submitted_at": null,
                        "accepted_at": null,
                        "reconciliation_required": false
                      },
                      "hash": "2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_text": "20100066603|01|F001|42|36.00|236.00|2026-10-09|6|20131312955|2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_image": "data:image/png;base64,iVBORw0KGgo=",
                      "links": {
                        "pdf": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5b/pdf",
                        "xml": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5b/xml",
                        "cdr": null
                      },
                      "affected_document_id": null,
                      "credit_note": null,
                      "debit_note": null,
                      "external_id": null,
                      "replaces_document_id": null,
                      "metadata": null,
                      "created_at": "2026-10-09T14:03:21.482913Z",
                      "updated_at": "2026-10-09T14:03:21.482913Z"
                    }
                  },
                  "factura_con_detracción": {
                    "summary": "Factura con detracción",
                    "description": "La respuesta es igual a la de una factura sin detracción, porque el documento no devuelve ese dato.",
                    "value": {
                      "id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5d",
                      "object": "document",
                      "environment": "test",
                      "company_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6b",
                      "type": "factura",
                      "series": "F001",
                      "number": 43,
                      "full_number": "F001-43",
                      "issue_date": "2026-10-09",
                      "currency": "PEN",
                      "customer": {
                        "document_type": "ruc",
                        "document_number": "20131312955",
                        "name": "Cliente S.A.C.",
                        "address": null,
                        "email": null
                      },
                      "items": [
                        {
                          "line_number": 1,
                          "product_code": null,
                          "description": "Servicio de estacionamiento mensual",
                          "quantity": 1,
                          "unit": "ZZ",
                          "unit_price": 1180,
                          "unit_value": 1000,
                          "tax_affectation": "gravado",
                          "igv_rate": 18.00,
                          "line_value": 1000.00,
                          "igv_amount": 180.00,
                          "line_total": 1180.00
                        }
                      ],
                      "totals": {
                        "taxable": 1000.00,
                        "exempt": 0.00,
                        "unaffected": 0.00,
                        "discount": 0.00,
                        "igv": 180.00,
                        "total": 1180.00,
                        "amount_in_words": "MIL CIENTO OCHENTA CON 00/100 SOLES"
                      },
                      "status": "issued",
                      "sunat_status": "pending",
                      "delivery_status": "none",
                      "sunat": {
                        "response_code": null,
                        "description": null,
                        "notes": [ ],
                        "deadline_at": "2026-10-13T04:59:59.000000Z",
                        "submitted_at": null,
                        "accepted_at": null,
                        "reconciliation_required": false
                      },
                      "hash": "2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_text": "20100066603|01|F001|43|180.00|1180.00|2026-10-09|6|20131312955|2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_image": "data:image/png;base64,iVBORw0KGgo=",
                      "links": {
                        "pdf": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5d/pdf",
                        "xml": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5d/xml",
                        "cdr": null
                      },
                      "affected_document_id": null,
                      "credit_note": null,
                      "debit_note": null,
                      "external_id": null,
                      "replaces_document_id": null,
                      "metadata": null,
                      "created_at": "2026-10-09T14:05:02.771046Z",
                      "updated_at": "2026-10-09T14:05:02.771046Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Solicitud mal formada. Códigos: `invalid_json`, `bad_request`, `idempotency_key_required`, `idempotency_key_invalid`. No se reintenta sin corregirla.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "idempotency_key_required": {
                    "summary": "idempotency_key_required",
                    "value": {
                      "error": {
                        "type": "bad_request",
                        "code": "idempotency_key_required",
                        "message": "Falta la cabecera Idempotency-Key.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:write que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflicto con un documento existente. `idempotency_in_progress` se reintenta con la misma clave unos segundos después. `external_id_conflict` no se reintenta: `document_id` señala el documento existente. `document_already_replaced` tampoco: `document_id` señala el reemplazo.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "idempotency_in_progress": {
                    "summary": "idempotency_in_progress",
                    "value": {
                      "error": {
                        "type": "conflict",
                        "code": "idempotency_in_progress",
                        "message": "La solicitud con esta Idempotency-Key todavía se está procesando. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: el cuerpo supera 256 KiB.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "payload_too_large": {
                    "summary": "payload_too_large",
                    "value": {
                      "error": {
                        "type": "payload_too_large",
                        "code": "payload_too_large",
                        "message": "El cuerpo supera el tamaño máximo: 256 KiB, o 2 MiB al subir un certificado, un logo o un CDR.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "`unsupported_media_type`: el cuerpo no llega con `Content-Type: application/json`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "unsupported_media_type": {
                    "summary": "unsupported_media_type",
                    "value": {
                      "error": {
                        "type": "unsupported_media_type",
                        "code": "unsupported_media_type",
                        "message": "El cuerpo debe enviarse con Content-Type application/json.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Datos no válidos: `error.param` señala el campo y `errors` lista todos los problemas si hay varios. El cuerpo corregido se envía con la misma `Idempotency-Key`, salvo en `idempotency_key_reused`: esa clave ya es de otra solicitud y repetirla devuelve el mismo error, así que se envía el cuerpo original o se usa una clave nueva.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "customer_document_required": {
                    "summary": "customer_document_required",
                    "value": {
                      "error": {
                        "type": "validation_error",
                        "code": "customer_document_required",
                        "message": "Una boleta mayor a S/ 700.00 requiere identificar al cliente con un documento admitido.",
                        "param": "customer.document_number",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable`, `storage_unavailable` o `encryption_unavailable`. Se reintenta con la misma `Idempotency-Key` y una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Lista los documentos del ambiente de la clave",
        "description": "Por defecto, el más reciente primero. Para sincronizar de forma incremental, usa `order=updated_at`, guarda el último `updated_at` visto, consulta desde ese valor con un solape de 2 minutos y descarta los repetidos por `id`. Los filtros se combinan. Sin `items` ni `qr_image`.\n\nRequiere el scope `documents:read`.",
        "operationId": "ListDocuments",
        "parameters": [
          {
            "name": "company_id",
            "in": "query",
            "description": "Filtra por empresa emisora, por su UUID; uno mal escrito responde `400 bad_request`.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filtra por tipo de comprobante. Un valor que no existe responde `422 filter_invalid` con su `param`.\n\n- `factura`: factura electrónica.\n- `boleta`: boleta de venta electrónica.\n- `nota_credito`: nota de crédito sobre una factura o una boleta.\n- `nota_debito`: nota de débito sobre una factura o una boleta.",
            "schema": {
              "enum": [
                "factura",
                "boleta",
                "nota_credito",
                "nota_debito"
              ],
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filtra por estado interno. Un valor que no existe responde `422 filter_invalid` con su `param`.\n\n- `issued`: emitido, numerado y con XML firmado. Es el estado inicial y el habitual.\n- `void_requested`: se pidió anularlo y se espera que SUNAT acepte la baja.\n- `voided`: SUNAT aceptó la anulación. Es un estado final.\n- `expired`: se confirmó que no hubo un envío válido dentro del plazo.",
            "schema": {
              "enum": [
                "issued",
                "void_requested",
                "voided",
                "expired"
              ],
              "type": "string"
            }
          },
          {
            "name": "sunat_status",
            "in": "query",
            "description": "Filtra por estado fiscal. Un valor que no existe responde `422 filter_invalid` con su `param`.\n\n- `pending`: pendiente de informar a SUNAT: una factura y sus notas se envían solas, y una boleta y sus notas van en el resumen diario. Se puede entregar al cliente aclarando que falta la validación.\n- `submitted`: enviado, o conciliando un resultado desconocido. No se reemite mientras el resultado sea incierto.\n- `accepted`: aceptado por SUNAT.\n- `accepted_with_observations`: aceptado con observaciones, que están en `sunat.notes`.\n- `rejected`: rechazado; el motivo está en `sunat.description` y el número no se reutiliza. Una factura o una boleta se corrige emitiendo otro documento con `replaces_document_id`. Una nota de crédito se corrige emitiendo otra nota, porque `replaces_document_id` no aplica y la rechazada no cuenta en el saldo del afectado.\n- `deadline_missed`: se confirmó que no hubo un envío válido en plazo. Contacta a soporte antes de pedir una baja o emitir otro documento.",
            "schema": {
              "enum": [
                "pending",
                "submitted",
                "accepted",
                "accepted_with_observations",
                "rejected",
                "deadline_missed"
              ],
              "type": "string"
            }
          },
          {
            "name": "series",
            "in": "query",
            "description": "Filtra por serie, como `B001`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "issue_date_from",
            "in": "query",
            "description": "Fecha de emisión desde. Fecha `YYYY-MM-DD` de Lima, incluida en el rango; una fecha mal escrita responde `400 bad_request`.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "issue_date_to",
            "in": "query",
            "description": "Fecha de emisión hasta. Fecha `YYYY-MM-DD` de Lima, incluida en el rango; una fecha mal escrita responde `400 bad_request`.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "external_id",
            "in": "query",
            "description": "Filtra por el identificador del integrador; sirve para recuperar una emisión. Uno en blanco responde `422 filter_invalid`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_from",
            "in": "query",
            "description": "Creación desde. Timestamp RFC 3339, incluido en el rango; una fecha mal escrita responde `400 bad_request`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_to",
            "in": "query",
            "description": "Creación hasta. Timestamp RFC 3339, incluido en el rango; una fecha mal escrita responde `400 bad_request`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_from",
            "in": "query",
            "description": "Última modificación desde. Timestamp RFC 3339, incluido en el rango; una fecha mal escrita responde `400 bad_request`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "updated_to",
            "in": "query",
            "description": "Última modificación hasta. Timestamp RFC 3339, incluido en el rango; una fecha mal escrita responde `400 bad_request`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "order",
            "in": "query",
            "description": "Cambia el orden. Un valor que no existe responde `422 filter_invalid` con su `param`.\n\n- `updated_at`: por última modificación ascendente, para sincronizar.",
            "schema": {
              "enum": [
                "updated_at"
              ],
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Tamaño de la página, de 1 a 200; por defecto 50. Fuera de ese rango responde `422 limit_invalid`, y un valor que no es un número, `400 bad_request`.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "El `next_cursor` de la página anterior. Es opaco y vale solo para el orden con el que se generó: otro responde `400 invalid_cursor`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Solicitud correcta.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PageOfDocumentDto"
                },
                "examples": {
                  "una_boleta": {
                    "summary": "Una boleta",
                    "value": {
                      "data": [
                        {
                          "id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5a",
                          "object": "document",
                          "environment": "test",
                          "company_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6b",
                          "type": "boleta",
                          "series": "B001",
                          "number": 125,
                          "full_number": "B001-125",
                          "issue_date": "2026-10-09",
                          "currency": "PEN",
                          "customer": {
                            "document_type": "dni",
                            "document_number": "45678912",
                            "name": "Juan Pérez",
                            "address": null,
                            "email": null
                          },
                          "totals": {
                            "taxable": 10.17,
                            "exempt": 0.00,
                            "unaffected": 0.00,
                            "discount": 0.00,
                            "igv": 1.83,
                            "total": 12.00,
                            "amount_in_words": "DOCE CON 00/100 SOLES"
                          },
                          "status": "issued",
                          "sunat_status": "pending",
                          "delivery_status": "none",
                          "sunat": {
                            "response_code": null,
                            "description": null,
                            "notes": [ ],
                            "deadline_at": "2026-10-17T04:59:59.000000Z",
                            "submitted_at": null,
                            "accepted_at": null,
                            "reconciliation_required": false
                          },
                          "hash": "2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                          "qr_text": "20100066603|03|B001|125|1.83|12.00|2026-10-09|1|45678912|2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                          "links": {
                            "pdf": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5a/pdf",
                            "xml": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5a/xml",
                            "cdr": null
                          },
                          "affected_document_id": null,
                          "credit_note": null,
                          "debit_note": null,
                          "external_id": "venta-98231",
                          "replaces_document_id": null,
                          "metadata": {
                            "placa": "ABC-123"
                          },
                          "created_at": "2026-10-09T14:03:21.482913Z",
                          "updated_at": "2026-10-09T14:03:21.482913Z"
                        }
                      ],
                      "next_cursor": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Solicitud mal formada. Códigos: `invalid_cursor` y `bad_request`, cuando un parámetro no tiene el formato de su tipo, como `limit=abc`. No se reintenta sin corregirla.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_cursor": {
                    "summary": "invalid_cursor",
                    "value": {
                      "error": {
                        "type": "bad_request",
                        "code": "invalid_cursor",
                        "message": "El cursor no es válido para este orden.",
                        "param": "cursor",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:read que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Parámetros no válidos: `error.param` señala cuál y `errors` lista todos los problemas si hay varios. Códigos: `filter_invalid`, `limit_invalid`, `field_invalid_characters`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "filter_invalid": {
                    "summary": "filter_invalid",
                    "value": {
                      "error": {
                        "type": "validation_error",
                        "code": "filter_invalid",
                        "message": "El filtro admite: factura, boleta, nota_credito, nota_debito.",
                        "param": "type",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable` o `storage_unavailable`. Se reintenta con una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/credit-notes": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Emite una nota de crédito sobre un documento aceptado",
        "description": "El afectado debe ser una factura o una boleta `issued`, con `sunat_status` en `accepted` o `accepted_with_observations` (`422 affected_document_not_accepted`, `422 affected_document_not_supported`). Ni el total ni lo gravado, lo exonerado o lo inafecto, cada uno por separado, pueden superar lo que queda del afectado después de sus notas no rechazadas (`422 credit_note_exceeds_affected`). El cliente y la moneda son los del afectado, y la nota va a SUNAT por el canal de este, con su plazo.\n\nRequiere el scope `documents:write`.",
        "operationId": "IssueCreditNote",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "UUID del documento afectado. Uno que no existe en el tenant y ambiente de la clave, o que no es un UUID, responde `404 not_found`.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Identifica la operación para reintentarla sin duplicarla durante 24 horas desde la respuesta final; se recomienda un UUID. De 1 a 128 caracteres `[A-Za-z0-9._:-]`. Sin ella responde `400 idempotency_key_required`, y con otro formato, `400 idempotency_key_invalid`. La misma clave con otra solicitud responde `422 idempotency_key_reused`, y con la primera aún en curso, `409 idempotency_in_progress`.",
            "required": true,
            "schema": {
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueCreditNoteCommand"
              },
              "examples": {
                "nota_de_crédito_por_el_total": {
                  "summary": "Nota de crédito por el total",
                  "value": {
                    "reason_code": "anulacion_operacion",
                    "reason": "Anulación de la operación"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Documento emitido y numerado. Con `Idempotent-Replayed: true`, es la respuesta guardada de la solicitud original.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentDto"
                },
                "examples": {
                  "nota_de_crédito": {
                    "summary": "Nota de crédito",
                    "value": {
                      "id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5c",
                      "object": "document",
                      "environment": "test",
                      "company_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6b",
                      "type": "nota_credito",
                      "series": "FC01",
                      "number": 7,
                      "full_number": "FC01-7",
                      "issue_date": "2026-10-09",
                      "currency": "PEN",
                      "customer": {
                        "document_type": "ruc",
                        "document_number": "20131312955",
                        "name": "Cliente S.A.C.",
                        "address": null,
                        "email": null
                      },
                      "items": [
                        {
                          "line_number": 1,
                          "product_code": null,
                          "description": "Servicio mensual",
                          "quantity": 2,
                          "unit": "ZZ",
                          "unit_price": 118,
                          "unit_value": 100,
                          "tax_affectation": "gravado",
                          "igv_rate": 18.00,
                          "line_value": 200.00,
                          "igv_amount": 36.00,
                          "line_total": 236.00
                        }
                      ],
                      "totals": {
                        "taxable": 200.00,
                        "exempt": 0.00,
                        "unaffected": 0.00,
                        "discount": 0.00,
                        "igv": 36.00,
                        "total": 236.00,
                        "amount_in_words": "DOSCIENTOS TREINTA Y SEIS CON 00/100 SOLES"
                      },
                      "status": "issued",
                      "sunat_status": "pending",
                      "delivery_status": "none",
                      "sunat": {
                        "response_code": null,
                        "description": null,
                        "notes": [ ],
                        "deadline_at": "2026-10-13T04:59:59.000000Z",
                        "submitted_at": null,
                        "accepted_at": null,
                        "reconciliation_required": false
                      },
                      "hash": "2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_text": "20100066603|07|FC01|7|36.00|236.00|2026-10-09|6|20131312955|2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_image": "data:image/png;base64,iVBORw0KGgo=",
                      "links": {
                        "pdf": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5c/pdf",
                        "xml": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5c/xml",
                        "cdr": null
                      },
                      "affected_document_id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5b",
                      "credit_note": {
                        "reason_code": "anulacion_operacion",
                        "reason": "Anulación de la operación"
                      },
                      "debit_note": null,
                      "external_id": null,
                      "replaces_document_id": null,
                      "metadata": null,
                      "created_at": "2026-10-09T15:42:10.204518Z",
                      "updated_at": "2026-10-09T15:42:10.204518Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Solicitud mal formada. Códigos: `invalid_json`, `bad_request`, `idempotency_key_required`, `idempotency_key_invalid`. No se reintenta sin corregirla.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "idempotency_key_required": {
                    "summary": "idempotency_key_required",
                    "value": {
                      "error": {
                        "type": "bad_request",
                        "code": "idempotency_key_required",
                        "message": "Falta la cabecera Idempotency-Key.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:write que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: no existe en el tenant y ambiente de la clave.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found",
                    "value": {
                      "error": {
                        "type": "not_found",
                        "code": "not_found",
                        "message": "El documento no existe.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflicto con un documento existente. `idempotency_in_progress` se reintenta con la misma clave unos segundos después. `external_id_conflict` no se reintenta: `document_id` señala el documento existente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "idempotency_in_progress": {
                    "summary": "idempotency_in_progress",
                    "value": {
                      "error": {
                        "type": "conflict",
                        "code": "idempotency_in_progress",
                        "message": "La solicitud con esta Idempotency-Key todavía se está procesando. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: el cuerpo supera 256 KiB.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "payload_too_large": {
                    "summary": "payload_too_large",
                    "value": {
                      "error": {
                        "type": "payload_too_large",
                        "code": "payload_too_large",
                        "message": "El cuerpo supera el tamaño máximo: 256 KiB, o 2 MiB al subir un certificado, un logo o un CDR.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "`unsupported_media_type`: el cuerpo no llega con `Content-Type: application/json`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "unsupported_media_type": {
                    "summary": "unsupported_media_type",
                    "value": {
                      "error": {
                        "type": "unsupported_media_type",
                        "code": "unsupported_media_type",
                        "message": "El cuerpo debe enviarse con Content-Type application/json.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Datos no válidos: `error.param` señala el campo y `errors` lista todos los problemas si hay varios. El cuerpo corregido se envía con la misma `Idempotency-Key`, salvo en `idempotency_key_reused`: esa clave ya es de otra solicitud y repetirla devuelve el mismo error, así que se envía el cuerpo original o se usa una clave nueva.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "affected_document_not_accepted": {
                    "summary": "affected_document_not_accepted",
                    "value": {
                      "error": {
                        "type": "validation_error",
                        "code": "affected_document_not_accepted",
                        "message": "El documento a modificar debe estar emitido y aceptado por SUNAT, con observaciones o sin ellas.",
                        "param": "id",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable`, `storage_unavailable` o `encryption_unavailable`. Se reintenta con la misma `Idempotency-Key` y una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/debit-notes": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Emite una nota de débito sobre un documento aceptado",
        "description": "Cobra de más sobre una venta ya emitida, como intereses por mora o un importe que quedó corto. El afectado debe ser una factura o una boleta `issued`, con `sunat_status` en `accepted` o `accepted_with_observations` (`422 affected_document_not_accepted`, `422 affected_document_not_supported`). La nota no tiene tope. El cliente, la moneda y la tasa del IGV son los del afectado, y la nota va a SUNAT por el canal de este, con su plazo, y se anula por el mismo camino.\n\nRequiere el scope `documents:write`.",
        "operationId": "IssueDebitNote",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "UUID del documento afectado. Uno que no existe en el tenant y ambiente de la clave, o que no es un UUID, responde `404 not_found`.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Identifica la operación para reintentarla sin duplicarla durante 24 horas desde la respuesta final; se recomienda un UUID. De 1 a 128 caracteres `[A-Za-z0-9._:-]`. Sin ella responde `400 idempotency_key_required`, y con otro formato, `400 idempotency_key_invalid`. La misma clave con otra solicitud responde `422 idempotency_key_reused`, y con la primera aún en curso, `409 idempotency_in_progress`.",
            "required": true,
            "schema": {
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueDebitNoteCommand"
              },
              "examples": {
                "intereses_por_mora": {
                  "summary": "Intereses por mora",
                  "value": {
                    "reason_code": "intereses_mora",
                    "reason": "Pago recibido 15 días después del vencimiento",
                    "items": [
                      {
                        "description": "Intereses por mora",
                        "quantity": 1,
                        "unit": "ZZ",
                        "unit_value": 10.00
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Documento emitido y numerado. Con `Idempotent-Replayed: true`, es la respuesta guardada de la solicitud original.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentDto"
                },
                "examples": {
                  "nota_de_débito": {
                    "summary": "Nota de débito",
                    "value": {
                      "id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5e",
                      "object": "document",
                      "environment": "test",
                      "company_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6b",
                      "type": "nota_debito",
                      "series": "FD01",
                      "number": 3,
                      "full_number": "FD01-3",
                      "issue_date": "2026-10-09",
                      "currency": "PEN",
                      "customer": {
                        "document_type": "ruc",
                        "document_number": "20131312955",
                        "name": "Cliente S.A.C.",
                        "address": null,
                        "email": null
                      },
                      "items": [
                        {
                          "line_number": 1,
                          "product_code": null,
                          "description": "Intereses por mora",
                          "quantity": 1,
                          "unit": "ZZ",
                          "unit_price": 11.8,
                          "unit_value": 10,
                          "tax_affectation": "gravado",
                          "igv_rate": 18.00,
                          "line_value": 10.00,
                          "igv_amount": 1.80,
                          "line_total": 11.80
                        }
                      ],
                      "totals": {
                        "taxable": 10.00,
                        "exempt": 0.00,
                        "unaffected": 0.00,
                        "discount": 0.00,
                        "igv": 1.80,
                        "total": 11.80,
                        "amount_in_words": "ONCE CON 80/100 SOLES"
                      },
                      "status": "issued",
                      "sunat_status": "pending",
                      "delivery_status": "none",
                      "sunat": {
                        "response_code": null,
                        "description": null,
                        "notes": [ ],
                        "deadline_at": "2026-10-13T04:59:59.000000Z",
                        "submitted_at": null,
                        "accepted_at": null,
                        "reconciliation_required": false
                      },
                      "hash": "2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_text": "20100066603|08|FD01|3|1.80|11.80|2026-10-09|6|20131312955|2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_image": "data:image/png;base64,iVBORw0KGgo=",
                      "links": {
                        "pdf": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5e/pdf",
                        "xml": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5e/xml",
                        "cdr": null
                      },
                      "affected_document_id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5b",
                      "credit_note": null,
                      "debit_note": {
                        "reason_code": "intereses_mora",
                        "reason": "Pago recibido 15 días después del vencimiento"
                      },
                      "external_id": null,
                      "replaces_document_id": null,
                      "metadata": null,
                      "created_at": "2026-10-09T16:02:31.118204Z",
                      "updated_at": "2026-10-09T16:02:31.118204Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Solicitud mal formada. Códigos: `invalid_json`, `bad_request`, `idempotency_key_required`, `idempotency_key_invalid`. No se reintenta sin corregirla.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "idempotency_key_required": {
                    "summary": "idempotency_key_required",
                    "value": {
                      "error": {
                        "type": "bad_request",
                        "code": "idempotency_key_required",
                        "message": "Falta la cabecera Idempotency-Key.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:write que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: no existe en el tenant y ambiente de la clave.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found",
                    "value": {
                      "error": {
                        "type": "not_found",
                        "code": "not_found",
                        "message": "El documento no existe.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflicto con un documento existente. `idempotency_in_progress` se reintenta con la misma clave unos segundos después. `external_id_conflict` no se reintenta: `document_id` señala el documento existente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "idempotency_in_progress": {
                    "summary": "idempotency_in_progress",
                    "value": {
                      "error": {
                        "type": "conflict",
                        "code": "idempotency_in_progress",
                        "message": "La solicitud con esta Idempotency-Key todavía se está procesando. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: el cuerpo supera 256 KiB.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "payload_too_large": {
                    "summary": "payload_too_large",
                    "value": {
                      "error": {
                        "type": "payload_too_large",
                        "code": "payload_too_large",
                        "message": "El cuerpo supera el tamaño máximo: 256 KiB, o 2 MiB al subir un certificado, un logo o un CDR.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "`unsupported_media_type`: el cuerpo no llega con `Content-Type: application/json`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "unsupported_media_type": {
                    "summary": "unsupported_media_type",
                    "value": {
                      "error": {
                        "type": "unsupported_media_type",
                        "code": "unsupported_media_type",
                        "message": "El cuerpo debe enviarse con Content-Type application/json.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Datos no válidos: `error.param` señala el campo y `errors` lista todos los problemas si hay varios. El cuerpo corregido se envía con la misma `Idempotency-Key`, salvo en `idempotency_key_reused`: esa clave ya es de otra solicitud y repetirla devuelve el mismo error, así que se envía el cuerpo original o se usa una clave nueva.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "affected_document_not_accepted": {
                    "summary": "affected_document_not_accepted",
                    "value": {
                      "error": {
                        "type": "validation_error",
                        "code": "affected_document_not_accepted",
                        "message": "El documento a modificar debe estar emitido y aceptado por SUNAT, con observaciones o sin ellas.",
                        "param": "id",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable`, `storage_unavailable` o `encryption_unavailable`. Se reintenta con la misma `Idempotency-Key` y una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Lee un documento",
        "description": "El documento completo, con ítems, estados y enlaces.\n\nRequiere el scope `documents:read`.",
        "operationId": "GetDocument",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "UUID del documento. Uno que no existe en el tenant y ambiente de la clave, o que no es un UUID, responde `404 not_found`.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Solicitud correcta.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentDto"
                },
                "examples": {
                  "boleta": {
                    "summary": "Boleta",
                    "value": {
                      "id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5a",
                      "object": "document",
                      "environment": "test",
                      "company_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6b",
                      "type": "boleta",
                      "series": "B001",
                      "number": 125,
                      "full_number": "B001-125",
                      "issue_date": "2026-10-09",
                      "currency": "PEN",
                      "customer": {
                        "document_type": "dni",
                        "document_number": "45678912",
                        "name": "Juan Pérez",
                        "address": null,
                        "email": null
                      },
                      "items": [
                        {
                          "line_number": 1,
                          "product_code": null,
                          "description": "Estacionamiento 2 horas",
                          "quantity": 1,
                          "unit": "ZZ",
                          "unit_price": 12,
                          "unit_value": 10.1694915254,
                          "tax_affectation": "gravado",
                          "igv_rate": 18.00,
                          "line_value": 10.17,
                          "igv_amount": 1.83,
                          "line_total": 12.00
                        }
                      ],
                      "totals": {
                        "taxable": 10.17,
                        "exempt": 0.00,
                        "unaffected": 0.00,
                        "discount": 0.00,
                        "igv": 1.83,
                        "total": 12.00,
                        "amount_in_words": "DOCE CON 00/100 SOLES"
                      },
                      "status": "issued",
                      "sunat_status": "pending",
                      "delivery_status": "none",
                      "sunat": {
                        "response_code": null,
                        "description": null,
                        "notes": [ ],
                        "deadline_at": "2026-10-17T04:59:59.000000Z",
                        "submitted_at": null,
                        "accepted_at": null,
                        "reconciliation_required": false
                      },
                      "hash": "2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_text": "20100066603|03|B001|125|1.83|12.00|2026-10-09|1|45678912|2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_image": "data:image/png;base64,iVBORw0KGgo=",
                      "links": {
                        "pdf": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5a/pdf",
                        "xml": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5a/xml",
                        "cdr": null
                      },
                      "affected_document_id": null,
                      "credit_note": null,
                      "debit_note": null,
                      "external_id": "venta-98231",
                      "replaces_document_id": null,
                      "metadata": {
                        "placa": "ABC-123"
                      },
                      "created_at": "2026-10-09T14:03:21.482913Z",
                      "updated_at": "2026-10-09T14:03:21.482913Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:read que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: no existe en el tenant y ambiente de la clave.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found",
                    "value": {
                      "error": {
                        "type": "not_found",
                        "code": "not_found",
                        "message": "El documento no existe.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable` o `storage_unavailable`. Se reintenta con una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/xml": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Descarga el XML firmado",
        "description": "Descarga `{ruc}-{tipo}-{serie}-{número}.xml`, disponible en todo documento emitido. `{tipo}` es el código de SUNAT: `01` en factura, `03` en boleta y `07` en nota de crédito.\n\nRequiere el scope `documents:read`.",
        "operationId": "GetDocumentXml",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "UUID del documento. Uno que no existe en el tenant y ambiente de la clave, o que no es un UUID, responde `404 not_found`.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Solicitud correcta.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/Stream"
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:read que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: no existe en el tenant y ambiente de la clave.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found",
                    "value": {
                      "error": {
                        "type": "not_found",
                        "code": "not_found",
                        "message": "El documento no existe.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable` o `storage_unavailable`. Se reintenta con una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/pdf": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Descarga el PDF",
        "description": "Descarga `{ruc}-{tipo}-{serie}-{número}.pdf`, o `{ruc}-{tipo}-{serie}-{número}-ticket.pdf` en formato ticket, disponible en todo documento emitido. `{tipo}` es el código de SUNAT: `01` en factura, `03` en boleta y `07` en nota de crédito. El de un comprobante `test` lleva la marca «PRUEBA – SIN VALOR FISCAL».\n\nRequiere el scope `documents:read`.",
        "operationId": "GetDocumentPdf",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "UUID del documento. Uno que no existe en el tenant y ambiente de la clave, o que no es un UUID, responde `404 not_found`.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "format",
            "in": "query",
            "description": "Formato del PDF. Otro valor responde `422 pdf_format_invalid`.\n\n- `a4`: hoja A4, el formato por defecto.\n- `ticket`: rollo de 80 mm para impresora térmica.",
            "schema": {
              "enum": [
                "a4",
                "ticket"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Solicitud correcta.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/pdf": {
                "schema": {
                  "$ref": "#/components/schemas/Stream"
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:read que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: no existe en el tenant y ambiente de la clave.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found",
                    "value": {
                      "error": {
                        "type": "not_found",
                        "code": "not_found",
                        "message": "El documento no existe.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`pdf_format_invalid`: `format` no es `a4` ni `ticket`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "pdf_format_invalid": {
                    "summary": "pdf_format_invalid",
                    "value": {
                      "error": {
                        "type": "validation_error",
                        "code": "pdf_format_invalid",
                        "message": "El formato del PDF debe ser a4 o ticket.",
                        "param": "format",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable` o `storage_unavailable`. Se reintenta con una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/cdr": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Descarga el CDR de SUNAT",
        "description": "Descarga `R-{ruc}-{tipo}-{serie}-{número}.zip`, la constancia tal como la devolvió SUNAT. `{tipo}` es el código de SUNAT: `01` en factura, `03` en boleta y `07` en nota de crédito. Responde `409 cdr_not_available` mientras SUNAT no haya respondido, y también en una boleta aceptada con una revisión manual de su resumen, que no tiene CDR. Para saber si un documento es válido, mira `sunat_status`.\n\nRequiere el scope `documents:read`.",
        "operationId": "GetDocumentCdr",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "UUID del documento. Uno que no existe en el tenant y ambiente de la clave, o que no es un UUID, responde `404 not_found`.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Solicitud correcta.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/zip": {
                "schema": {
                  "$ref": "#/components/schemas/Stream"
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:read que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: no existe en el tenant y ambiente de la clave.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found",
                    "value": {
                      "error": {
                        "type": "not_found",
                        "code": "not_found",
                        "message": "El documento no existe.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`cdr_not_available`: el documento no tiene CDR. Vuelve a pedirlo cuando SUNAT responda; una boleta aceptada con una revisión manual de su resumen no lo tiene.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "cdr_not_available": {
                    "summary": "cdr_not_available",
                    "value": {
                      "error": {
                        "type": "conflict",
                        "code": "cdr_not_available",
                        "message": "El documento no tiene CDR: SUNAT todavía no respondió o, en una boleta, se confirmó en SUNAT sin la constancia de su resumen.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable` o `storage_unavailable`. Se reintenta con una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/void": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Solicita la baja de un documento aceptado",
        "description": "Solo documentos ya aceptados por SUNAT; uno pendiente, con resultado desconocido o fuera de plazo responde `409 document_not_voidable`, y uno ya anulado o en anulación, `409 document_already_voided`. Una factura o una nota sobre factura se admite hasta 3 horas antes del fin del séptimo día de su emisión; una boleta o una nota sobre boleta, si SUNAT recibe el resumen dentro de los 7 días de su emisión. El resultado llega por `status` y `sunat_status`, y por los webhooks `document.voided` o `document.void_rejected`.\n\nRequiere el scope `documents:write`.",
        "operationId": "RequestDocumentVoid",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "UUID del documento que se anula. Uno que no existe en el tenant y ambiente de la clave, o que no es un UUID, responde `404 not_found`.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Identifica la operación para reintentarla sin duplicarla durante 24 horas desde la respuesta final; se recomienda un UUID. De 1 a 128 caracteres `[A-Za-z0-9._:-]`. Sin ella responde `400 idempotency_key_required`, y con otro formato, `400 idempotency_key_invalid`. La misma clave con otra solicitud responde `422 idempotency_key_reused`, y con la primera aún en curso, `409 idempotency_in_progress`.",
            "required": true,
            "schema": {
              "maxLength": 128,
              "pattern": "^[A-Za-z0-9._:-]+$",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestVoidCommand"
              },
              "examples": {
                "baja": {
                  "summary": "Baja",
                  "value": {
                    "reason": "Error en los datos del cliente"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Baja solicitada: el documento queda en `status = void_requested`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Idempotent-Replayed": {
                "$ref": "#/components/headers/Idempotent-Replayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentDto"
                },
                "examples": {
                  "baja_solicitada": {
                    "summary": "Baja solicitada",
                    "value": {
                      "id": "0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5b",
                      "object": "document",
                      "environment": "test",
                      "company_id": "0192f0b1-2d4c-7a1e-8b3f-1c2d3e4f5a6b",
                      "type": "factura",
                      "series": "F001",
                      "number": 42,
                      "full_number": "F001-42",
                      "issue_date": "2026-10-09",
                      "currency": "PEN",
                      "customer": {
                        "document_type": "ruc",
                        "document_number": "20131312955",
                        "name": "Cliente S.A.C.",
                        "address": null,
                        "email": null
                      },
                      "items": [
                        {
                          "line_number": 1,
                          "product_code": null,
                          "description": "Servicio mensual",
                          "quantity": 2,
                          "unit": "ZZ",
                          "unit_price": 118,
                          "unit_value": 100,
                          "tax_affectation": "gravado",
                          "igv_rate": 18.00,
                          "line_value": 200.00,
                          "igv_amount": 36.00,
                          "line_total": 236.00
                        }
                      ],
                      "totals": {
                        "taxable": 200.00,
                        "exempt": 0.00,
                        "unaffected": 0.00,
                        "discount": 0.00,
                        "igv": 36.00,
                        "total": 236.00,
                        "amount_in_words": "DOSCIENTOS TREINTA Y SEIS CON 00/100 SOLES"
                      },
                      "status": "void_requested",
                      "sunat_status": "accepted",
                      "delivery_status": "none",
                      "sunat": {
                        "response_code": "0",
                        "description": "La Factura numero F001-42, ha sido aceptada",
                        "notes": [ ],
                        "deadline_at": "2026-10-13T04:59:59.000000Z",
                        "submitted_at": "2026-10-09T14:03:25.102938Z",
                        "accepted_at": "2026-10-09T14:03:27.562910Z",
                        "reconciliation_required": false
                      },
                      "hash": "2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_text": "20100066603|01|F001|42|36.00|236.00|2026-10-09|6|20131312955|2/tssig+2hIBSmZyIT0CWMhsTMnRKmApc0tdWRsDs4U=",
                      "qr_image": "data:image/png;base64,iVBORw0KGgo=",
                      "links": {
                        "pdf": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5b/pdf",
                        "xml": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5b/xml",
                        "cdr": "/v1/documents/0192f1a2-7c3e-7d4b-9a8f-2b6c1d0e4f5b/cdr"
                      },
                      "affected_document_id": null,
                      "credit_note": null,
                      "debit_note": null,
                      "external_id": null,
                      "replaces_document_id": null,
                      "metadata": null,
                      "created_at": "2026-10-09T14:03:21.482913Z",
                      "updated_at": "2026-10-09T16:10:04.318204Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Solicitud mal formada. Códigos: `invalid_json`, `bad_request`, `idempotency_key_required`, `idempotency_key_invalid`. No se reintenta sin corregirla.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "idempotency_key_required": {
                    "summary": "idempotency_key_required",
                    "value": {
                      "error": {
                        "type": "bad_request",
                        "code": "idempotency_key_required",
                        "message": "Falta la cabecera Idempotency-Key.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:write que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: no existe en el tenant y ambiente de la clave.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found",
                    "value": {
                      "error": {
                        "type": "not_found",
                        "code": "not_found",
                        "message": "El documento no existe.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflicto con el estado del documento. `idempotency_in_progress` se reintenta con la misma clave unos segundos después. `document_not_voidable` y `document_already_voided` no se reintentan mientras ese estado no cambie.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "document_not_voidable": {
                    "summary": "document_not_voidable",
                    "value": {
                      "error": {
                        "type": "conflict",
                        "code": "document_not_voidable",
                        "message": "El documento todavía no está aceptado por SUNAT: se anula después de que lo acepte, o no se anula si lo rechazó.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: el cuerpo supera 256 KiB.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "payload_too_large": {
                    "summary": "payload_too_large",
                    "value": {
                      "error": {
                        "type": "payload_too_large",
                        "code": "payload_too_large",
                        "message": "El cuerpo supera el tamaño máximo: 256 KiB, o 2 MiB al subir un certificado, un logo o un CDR.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "`unsupported_media_type`: el cuerpo no llega con `Content-Type: application/json`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "unsupported_media_type": {
                    "summary": "unsupported_media_type",
                    "value": {
                      "error": {
                        "type": "unsupported_media_type",
                        "code": "unsupported_media_type",
                        "message": "El cuerpo debe enviarse con Content-Type application/json.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Datos no válidos: `error.param` señala el campo y `errors` lista todos los problemas si hay varios. El cuerpo corregido se envía con la misma `Idempotency-Key`, salvo en `idempotency_key_reused`: esa clave ya es de otra solicitud y repetirla devuelve el mismo error, así que se envía el cuerpo original o se usa una clave nueva.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "field_required": {
                    "summary": "field_required",
                    "value": {
                      "error": {
                        "type": "validation_error",
                        "code": "field_required",
                        "message": "El campo es obligatorio.",
                        "param": "reason",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`rate_limited`: se superó el límite de 600 solicitudes por minuto por clave o 1200 por IP. Se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "rate_limited",
                        "message": "Demasiadas solicitudes. Reintente después de los segundos que indica Retry-After.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable`, `storage_unavailable` o `encryption_unavailable`. Se reintenta con la misma `Idempotency-Key` y una espera creciente.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/email": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Envía el comprobante por correo",
        "description": "Encola el envío del PDF A4 y el XML al correo del cliente del documento o al de `email`, a nombre de la empresa y con su correo como respuesta. Responde de inmediato: `status` queda en `pending` y el correo sale en segundos, o al día siguiente si la plataforma llegó a su tope diario de correos a clientes. Hasta 5 envíos por documento y día de Lima (`429 document_email_limit_reached`). No depende de la opción de envío automático de la empresa, pero sigue su regla: una factura o una nota sobre factura se envía cuando SUNAT la acepta, y antes responde `409 document_email_document_not_accepted`; uno rechazado, fuera de plazo, anulado o en anulación responde `409 document_email_document_invalid`, y si eso pasa mientras espera, queda en `skipped`. En `test`, el asunto empieza con `[PRUEBA]` y el envío cuenta para el tope de 20 correos diarios de la cuenta: pasado ese tope, queda en `skipped`.\n\nRequiere el scope `documents:write`.",
        "operationId": "SendDocumentEmail",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "UUID del documento que se envía. Uno que no existe en el tenant y ambiente de la clave, o que no es un UUID, responde `404 not_found`.",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/SendDocumentEmailCommand"
                  }
                ]
              },
              "examples": {
                "a_otro_correo": {
                  "summary": "A otro correo",
                  "value": {
                    "email": "compras@cliente.example"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Envío encolado, con `status = pending`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentEmailDto"
                },
                "examples": {
                  "envío_encolado": {
                    "summary": "Envío encolado",
                    "value": {
                      "id": "0192f1a2-9d14-7a61-b3c2-5e8f7a6b4c3d",
                      "recipient": "compras@cliente.example",
                      "origin": "manual",
                      "status": "pending",
                      "error": null,
                      "created_at": "2026-10-09T16:20:41.507311Z",
                      "sent_at": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Solicitud mal formada. Códigos: `invalid_json` y `bad_request`. No se reintenta sin corregirla.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_json": {
                    "summary": "invalid_json",
                    "value": {
                      "error": {
                        "type": "bad_request",
                        "code": "invalid_json",
                        "message": "El cuerpo no es un JSON válido.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sin una API key válida. Códigos: `unauthorized`, `invalid_api_key`, `revoked_api_key`, `expired_api_key`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "invalid_api_key": {
                    "summary": "invalid_api_key",
                    "value": {
                      "error": {
                        "type": "unauthorized",
                        "code": "invalid_api_key",
                        "message": "La API key no es válida.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La clave no puede operar. Códigos: `forbidden` (no tiene el scope), `tenant_suspended`, `plan_without_api` (el plan de la cuenta no incluye la API), `account_not_activated` (emisión en `live` de una cuenta que Boletura todavía no activó).",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "forbidden": {
                    "summary": "forbidden",
                    "value": {
                      "error": {
                        "type": "forbidden",
                        "code": "forbidden",
                        "message": "La API key no tiene el scope documents:write que exige este endpoint.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "`not_found`: no existe en el tenant y ambiente de la clave.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found",
                    "value": {
                      "error": {
                        "type": "not_found",
                        "code": "not_found",
                        "message": "El documento no existe.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Conflicto con el estado del documento. `document_email_document_not_accepted`: SUNAT todavía no aceptó la factura o la nota sobre factura; se reintenta cuando `sunat_status` sea `accepted` o `accepted_with_observations`. `document_email_document_invalid`: SUNAT lo rechazó, venció su plazo de envío, o está anulado o en anulación; no se reintenta mientras ese estado no cambie.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "document_email_document_not_accepted": {
                    "summary": "document_email_document_not_accepted",
                    "value": {
                      "error": {
                        "type": "conflict",
                        "code": "document_email_document_not_accepted",
                        "message": "SUNAT todavía no aceptó el comprobante: una factura o una nota sobre factura se envía por correo cuando SUNAT la acepta.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "`payload_too_large`: el cuerpo supera 256 KiB.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "payload_too_large": {
                    "summary": "payload_too_large",
                    "value": {
                      "error": {
                        "type": "payload_too_large",
                        "code": "payload_too_large",
                        "message": "El cuerpo supera el tamaño máximo: 256 KiB, o 2 MiB al subir un certificado, un logo o un CDR.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "415": {
            "description": "`unsupported_media_type`: el cuerpo no llega con `Content-Type: application/json`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "unsupported_media_type": {
                    "summary": "unsupported_media_type",
                    "value": {
                      "error": {
                        "type": "unsupported_media_type",
                        "code": "unsupported_media_type",
                        "message": "El cuerpo debe enviarse con Content-Type application/json.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Datos no válidos: `error.param` señala el campo. Códigos: `document_email_recipient_required`, cuando el documento no tiene correo del cliente y no se envía `email`; `document_email_customer_email_invalid`, cuando no se envía `email` y el correo del cliente del documento está mal escrito, y los de un `email` mal escrito.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "document_email_recipient_required": {
                    "summary": "document_email_recipient_required",
                    "value": {
                      "error": {
                        "type": "validation_error",
                        "code": "document_email_recipient_required",
                        "message": "El comprobante no tiene correo del cliente: indica a qué correo enviarlo.",
                        "param": "email",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "`document_email_limit_reached`: el documento ya se envió 5 veces hoy a pedido; se reintenta al día siguiente de Lima. También `rate_limited`, si se superó el límite de solicitudes, que se reintenta después de `Retry-After`.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "document_email_limit_reached": {
                    "summary": "document_email_limit_reached",
                    "value": {
                      "error": {
                        "type": "rate_limited",
                        "code": "document_email_limit_reached",
                        "message": "El comprobante ya se envió 5 veces hoy a pedido: vuelve a intentarlo mañana.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Falla transitoria, como `database_unavailable`. Se reintenta con una espera creciente; un reintento después de una respuesta perdida puede enviar el correo otra vez.",
            "headers": {
              "X-Request-Id": {
                "$ref": "#/components/headers/X-Request-Id"
              },
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "database_unavailable": {
                    "summary": "database_unavailable",
                    "value": {
                      "error": {
                        "type": "unavailable",
                        "code": "database_unavailable",
                        "message": "La base de datos no está disponible. Reintente en unos segundos.",
                        "request_id": "req_0192f1a27c3e7d4b9a8f2b6c1d0e4f5a"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CompanyStatus": {
        "enum": [
          "draft",
          "ready",
          "suspended"
        ],
        "description": "Estado de la empresa emisora.\n\n- `draft`: todavía no habilitada en `live`.\n- `ready`: habilitada en `live`.\n- `suspended`: detenida; no puede emitir."
      },
      "CreditNoteReason": {
        "enum": [
          "anulacion_operacion",
          "anulacion_error_ruc",
          "correccion_descripcion",
          "descuento_global",
          "descuento_item",
          "devolucion_total",
          "devolucion_item",
          "bonificacion",
          "disminucion_valor",
          "otros"
        ],
        "description": "Motivo de la nota de crédito.\n\n- `anulacion_operacion`: anulación de la operación.\n- `anulacion_error_ruc`: anulación por error en el RUC.\n- `correccion_descripcion`: corrección por error en la descripción.\n- `descuento_global`: descuento global. No se admite sobre una boleta.\n- `descuento_item`: descuento por ítem. No se admite sobre una boleta.\n- `devolucion_total`: devolución total.\n- `devolucion_item`: devolución por ítem.\n- `bonificacion`: bonificación. No se admite sobre una boleta.\n- `disminucion_valor`: disminución en el valor.\n- `otros`: otros conceptos."
      },
      "CustomerDocumentType": {
        "enum": [
          "dni",
          "ruc",
          "ce",
          "pasaporte",
          "otros",
          "none"
        ],
        "description": "Tipo de documento del cliente.\n\n- `dni`: documento nacional de identidad, de 8 dígitos.\n- `ruc`: RUC, de 11 dígitos con dígito verificador válido.\n- `ce`: carné de extranjería, de hasta 30 caracteres.\n- `pasaporte`: pasaporte, de hasta 30 caracteres.\n- `otros`: otro documento. Hoy ningún comprobante lo admite: una boleta responde `422 customer_document_type_not_supported` y una factura exige `ruc`.\n- `none`: cliente sin documento, sin `document_number`."
      },
      "DebitNoteReason": {
        "enum": [
          "intereses_mora",
          "aumento_valor",
          "penalidades"
        ],
        "description": "Motivo de la nota de débito.\n\n- `intereses_mora`: intereses por mora.\n- `aumento_valor`: aumento en el valor.\n- `penalidades`: penalidades. La nota es inafecta: un ítem sin `tax_affectation` va inafecto y uno gravado o exonerado responde `422 debit_note_penalty_not_inafecto`."
      },
      "DeliveryStatus": {
        "enum": [
          "none",
          "pending",
          "delivered",
          "failed"
        ],
        "description": "Entrega del último evento del documento por webhook.\n\n- `none`: todavía no se creó ninguna entrega.\n- `pending`: alguna entrega sigue en curso.\n- `delivered`: todas las entregas respondieron 2xx.\n- `failed`: alguna entrega agotó sus reintentos o se abandonó."
      },
      "DetractionInput": {
        "required": [
          "code"
        ],
        "type": "object",
        "properties": {
          "code": {
            "enum": [
              "022",
              "037"
            ],
            "type": "string",
            "description": "Código de la operación sujeta; quien emite declara si aplica. Solo facturas, con un total de más de S/ 700 con IGV y todos los ítems gravados. Otro código responde `422 detraction_code_invalid`; una boleta, `422 detraction_not_allowed`; un total menor, `422 detraction_amount_too_low`; un ítem no gravado, `422 detraction_items_not_taxed`; y una empresa sin cuenta de detracciones, `422 detraction_account_required`.\n\n- `022`: otros servicios empresariales.\n- `037`: demás servicios gravados con el IGV."
          }
        },
        "description": "Detracción de una factura. La plataforma calcula el 12 % del total con IGV, redondeado a dos decimales, y usa la cuenta de detracciones de la empresa; el depósito sigue fuera de la plataforma."
      },
      "DocumentCreditNoteDto": {
        "required": [
          "reason_code",
          "reason"
        ],
        "type": "object",
        "properties": {
          "reason_code": {
            "description": "Motivo de la nota.",
            "$ref": "#/components/schemas/CreditNoteReason"
          },
          "reason": {
            "type": "string",
            "description": "Descripción libre del motivo."
          }
        },
        "description": "Datos propios de una nota de crédito."
      },
      "DocumentCustomerDto": {
        "required": [
          "document_type",
          "document_number",
          "name",
          "address",
          "email"
        ],
        "type": "object",
        "properties": {
          "document_type": {
            "description": "Tipo de documento del cliente.",
            "$ref": "#/components/schemas/CustomerDocumentType"
          },
          "document_number": {
            "type": [
              "null",
              "string"
            ],
            "description": "Número de documento; nulo si el cliente no tiene."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nombre o razón social."
          },
          "address": {
            "type": [
              "null",
              "string"
            ],
            "description": "Dirección."
          },
          "email": {
            "type": [
              "null",
              "string"
            ],
            "description": "Correo."
          }
        },
        "description": "Cliente del comprobante, tal como quedó al emitir."
      },
      "DocumentCustomerInput": {
        "required": [
          "document_type"
        ],
        "type": "object",
        "properties": {
          "document_type": {
            "enum": [
              "dni",
              "ruc",
              "ce",
              "pasaporte",
              "otros",
              "none"
            ],
            "type": "string",
            "description": "Tipo de documento. Otro valor responde `422 customer_document_type_invalid`, salvo cuando el comprobante exige un tipo: una factura responde `422 customer_ruc_required`, y una boleta de más de S/ 700 con IGV, `422 customer_document_required`.\n\n- `dni`: documento nacional de identidad, de 8 dígitos.\n- `ruc`: RUC, de 11 dígitos con dígito verificador válido.\n- `ce`: carné de extranjería, de hasta 30 caracteres.\n- `pasaporte`: pasaporte, de hasta 30 caracteres.\n- `otros`: otro documento. Hoy ningún comprobante lo admite: una boleta responde `422 customer_document_type_not_supported` y una factura exige `ruc`.\n- `none`: cliente sin documento, sin `document_number`."
          },
          "document_number": {
            "type": [
              "null",
              "string"
            ],
            "description": "Número de documento. DNI de 8 dígitos (`422 dni_invalid`), RUC de 11 dígitos con dígito verificador válido (`422 ruc_invalid`), carné de extranjería o pasaporte de hasta 30 caracteres (`422 field_too_long`), sin saltos de línea ni tabuladores (`422 field_invalid_characters`). No admite `|`, y con `none` no se envía (`422 customer_document_number_invalid`). Se recorta en los extremos."
          },
          "name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nombre o razón social, de 3 a 200 caracteres (`422 field_too_short`, `422 field_too_long`), sin saltos de línea ni tabuladores (`422 field_invalid_characters`). Obligatorio si el cliente tiene documento (`422 field_required`). En `test`, los valores `SIMULAR RECHAZO`, `SIMULAR OBSERVACIONES`, `SIMULAR TIMEOUT` y `SIMULAR VENCIMIENTO` simulan ese resultado sin ir a SUNAT beta; en `live` son un nombre cualquiera. En una boleta, el caso actúa sobre su resumen diario: `SIMULAR OBSERVACIONES` y `SIMULAR TIMEOUT` alcanzan a todas las boletas del resumen, y `SIMULAR RECHAZO` devuelve las demás a `pending`."
          },
          "address": {
            "type": [
              "null",
              "string"
            ],
            "description": "Dirección, de hasta 500 caracteres (`422 field_too_long`), sin saltos de línea ni tabuladores (`422 field_invalid_characters`)."
          },
          "email": {
            "type": [
              "null",
              "string"
            ],
            "description": "Correo, de hasta 254 caracteres (`422 field_too_long`), sin saltos de línea ni tabuladores (`422 field_invalid_characters`)."
          }
        },
        "description": "Cliente del comprobante. Si se envía, `document_type` es obligatorio (`422 field_required`).\n\n- Factura: `document_type` `ruc`, `document_number` y `name` obligatorios (`422 customer_ruc_required`, `422 field_required`).\n- Boleta de más de S/ 700 con IGV: `name` y un documento `dni`, `ce`, `pasaporte` o `ruc` (`422 customer_document_required`, `422 field_required`).\n- Boleta de S/ 700 o menos: se puede omitir, o enviar con `none`, y se usa la representación de cliente no identificado, con el `name` que se envíe."
      },
      "DocumentDebitNoteDto": {
        "required": [
          "reason_code",
          "reason"
        ],
        "type": "object",
        "properties": {
          "reason_code": {
            "description": "Motivo de la nota.",
            "$ref": "#/components/schemas/DebitNoteReason"
          },
          "reason": {
            "type": "string",
            "description": "Descripción libre del motivo."
          }
        },
        "description": "Datos propios de una nota de débito."
      },
      "DocumentDto": {
        "required": [
          "id",
          "object",
          "environment",
          "company_id",
          "type",
          "series",
          "number",
          "full_number",
          "issue_date",
          "currency",
          "customer",
          "totals",
          "status",
          "sunat_status",
          "delivery_status",
          "sunat",
          "hash",
          "qr_text",
          "links",
          "affected_document_id",
          "credit_note",
          "debit_note",
          "external_id",
          "replaces_document_id",
          "metadata",
          "created_at",
          "updated_at"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "UUID del documento.",
            "format": "uuid"
          },
          "object": {
            "type": "string",
            "description": "Siempre `document`."
          },
          "environment": {
            "description": "Ambiente del documento. Uno de `test` no se ve con una clave `live`, ni al revés.",
            "$ref": "#/components/schemas/FiscalEnvironment"
          },
          "company_id": {
            "type": "string",
            "description": "UUID de la empresa emisora.",
            "format": "uuid"
          },
          "type": {
            "description": "Tipo de comprobante.",
            "$ref": "#/components/schemas/DocumentType"
          },
          "series": {
            "type": "string",
            "description": "Serie, como `B001`."
          },
          "number": {
            "type": "integer",
            "description": "Correlativo dentro de la serie.",
            "format": "int64"
          },
          "full_number": {
            "type": "string",
            "description": "Serie y correlativo, como `B001-125`."
          },
          "issue_date": {
            "type": "string",
            "description": "Fecha de emisión, en fecha civil de Lima.",
            "format": "date"
          },
          "currency": {
            "type": "string",
            "description": "Moneda; hoy siempre `PEN`."
          },
          "customer": {
            "description": "Cliente del comprobante.",
            "$ref": "#/components/schemas/DocumentCustomerDto"
          },
          "items": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/DocumentItemDto"
            },
            "description": "Líneas del comprobante. No aparece en el listado."
          },
          "totals": {
            "description": "Totales calculados por la plataforma.",
            "$ref": "#/components/schemas/DocumentTotalsDto"
          },
          "status": {
            "description": "Estado interno.",
            "$ref": "#/components/schemas/DocumentStatus"
          },
          "sunat_status": {
            "description": "Estado fiscal. Es el campo que dice si el documento es válido.",
            "$ref": "#/components/schemas/SunatStatus"
          },
          "delivery_status": {
            "description": "Estado de la entrega por webhook.",
            "$ref": "#/components/schemas/DeliveryStatus"
          },
          "sunat": {
            "description": "Detalle del envío a SUNAT.",
            "$ref": "#/components/schemas/DocumentSunatDto"
          },
          "hash": {
            "type": "string",
            "description": "Valor de resumen de la firma del XML (`DigestValue`)."
          },
          "qr_text": {
            "type": "string",
            "description": "Texto del QR del comprobante, con sus campos separados por `|`."
          },
          "qr_image": {
            "type": [
              "null",
              "string"
            ],
            "description": "PNG del QR como data URI. No aparece en el listado."
          },
          "links": {
            "description": "Enlaces de descarga.",
            "$ref": "#/components/schemas/DocumentLinksDto"
          },
          "affected_document_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "En una nota de crédito o de débito, el documento que afecta; si no, nulo.",
            "format": "uuid"
          },
          "credit_note": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/DocumentCreditNoteDto"
              }
            ],
            "description": "Motivo de la nota de crédito; nulo en los demás comprobantes."
          },
          "debit_note": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/DocumentDebitNoteDto"
              }
            ],
            "description": "Motivo de la nota de débito; nulo en los demás comprobantes."
          },
          "external_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identificador del integrador; nulo si no se envió."
          },
          "replaces_document_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Documento rechazado que este reemplaza; nulo si no reemplaza a ninguno.",
            "format": "uuid"
          },
          "metadata": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/JsonElement"
              }
            ],
            "description": "El objeto que envió el integrador; nulo si no envió ninguno."
          },
          "created_at": {
            "type": "string",
            "description": "Creación. Timestamp RFC 3339 en UTC, con seis decimales.",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "description": "Última modificación. Timestamp RFC 3339 en UTC, con seis decimales.",
            "format": "date-time"
          }
        },
        "description": "Comprobante electrónico: una boleta, una factura, una nota de crédito o una nota de débito."
      },
      "DocumentEmailDto": {
        "required": [
          "id",
          "recipient",
          "origin",
          "status",
          "error",
          "created_at",
          "sent_at"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "UUID del envío.",
            "format": "uuid"
          },
          "recipient": {
            "type": "string",
            "description": "Correo de destino."
          },
          "origin": {
            "description": "Quién originó el envío.",
            "$ref": "#/components/schemas/DocumentEmailOrigin"
          },
          "status": {
            "description": "Estado del envío.",
            "$ref": "#/components/schemas/DocumentEmailStatus"
          },
          "error": {
            "type": [
              "null",
              "string"
            ],
            "description": "Motivo de `failed` o `skipped`; nulo en los demás estados."
          },
          "created_at": {
            "type": "string",
            "description": "Cuándo se pidió. Timestamp RFC 3339 en UTC, con seis decimales.",
            "format": "date-time"
          },
          "sent_at": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cuándo lo recibió el servidor de correo; nulo mientras no se envía. Timestamp RFC 3339 en UTC, con seis decimales.",
            "format": "date-time"
          }
        },
        "description": "Un envío del documento por correo."
      },
      "DocumentEmailOrigin": {
        "enum": [
          "automatic",
          "manual"
        ],
        "description": "Quién originó el envío.\n\n- `automatic`: la plataforma, porque la empresa tiene activo el envío al cliente.\n- `manual`: una solicitud de esta API o del back office."
      },
      "DocumentEmailStatus": {
        "enum": [
          "pending",
          "sent",
          "failed",
          "skipped"
        ],
        "description": "Estado del envío.\n\n- `pending`: encolado; todavía no salió.\n- `sent`: el servidor de correo lo recibió. No confirma que llegó a la bandeja.\n- `failed`: no salió, porque el servidor de correo lo rechazó o la dirección no es válida; el motivo está en `error`.\n- `skipped`: no se envió, como pasa en `test` cuando la cuenta llegó a su tope diario de correos, o si el documento perdió su validez antes de salir; el motivo está en `error`."
      },
      "DocumentItemDto": {
        "required": [
          "line_number",
          "product_code",
          "description",
          "quantity",
          "unit",
          "unit_price",
          "unit_value",
          "tax_affectation",
          "igv_rate",
          "line_value",
          "igv_amount",
          "line_total"
        ],
        "type": "object",
        "properties": {
          "line_number": {
            "type": "integer",
            "description": "Número de línea, desde 1.",
            "format": "int32"
          },
          "product_code": {
            "type": [
              "null",
              "string"
            ],
            "description": "Código interno del integrador; nulo si el ítem no lo trajo."
          },
          "description": {
            "type": "string",
            "description": "Descripción de la línea."
          },
          "quantity": {
            "type": "number",
            "description": "Cantidad, sin ceros finales."
          },
          "unit": {
            "type": "string",
            "description": "Código de unidad de medida."
          },
          "unit_price": {
            "type": "number",
            "description": "Precio unitario con IGV, sin ceros finales."
          },
          "unit_value": {
            "type": "number",
            "description": "Valor unitario sin IGV, sin ceros finales."
          },
          "tax_affectation": {
            "description": "Afectación al IGV.",
            "$ref": "#/components/schemas/ItemTaxAffectation"
          },
          "igv_rate": {
            "type": "number",
            "description": "Tasa del IGV en porcentaje, como `18`."
          },
          "line_value": {
            "type": "number",
            "description": "Valor de la línea sin IGV, con 2 decimales."
          },
          "igv_amount": {
            "type": "number",
            "description": "IGV de la línea, con 2 decimales."
          },
          "line_total": {
            "type": "number",
            "description": "Total de la línea con IGV, con 2 decimales."
          }
        },
        "description": "Línea del comprobante, con los importes calculados por la plataforma."
      },
      "DocumentItemInput": {
        "required": [
          "description",
          "quantity"
        ],
        "type": "object",
        "properties": {
          "description": {
            "type": "string",
            "description": "Descripción de la línea, de hasta 500 caracteres, sin saltos de línea ni tabuladores (`422 field_too_long`, `422 field_invalid_characters`)."
          },
          "quantity": {
            "type": "number",
            "description": "Cantidad mayor que 0, con hasta 12 enteros y 3 decimales (`422 quantity_invalid`). Va como número JSON, nunca entre comillas (`400 invalid_json`)."
          },
          "unit": {
            "type": [
              "null",
              "string"
            ],
            "description": "Código de unidad de medida del catálogo 03 de SUNAT; por defecto `NIU`. Para servicios, `ZZ`. No distingue mayúsculas. Uno que no existe responde `422 unit_invalid`."
          },
          "unit_price": {
            "type": [
              "null",
              "number"
            ],
            "description": "Precio unitario **con** IGV incluido, mayor que 0, con hasta 12 enteros y 10 decimales (`422 amount_invalid`)."
          },
          "unit_value": {
            "type": [
              "null",
              "number"
            ],
            "description": "Valor unitario **sin** IGV, mayor que 0, con hasta 12 enteros y 10 decimales (`422 amount_invalid`)."
          },
          "tax_affectation": {
            "enum": [
              "gravado",
              "exonerado",
              "inafecto"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Afectación al IGV; por defecto `gravado`. Otro valor responde `422 tax_affectation_invalid`.\n\n- `gravado`: paga IGV.\n- `exonerado`: exonerado de IGV.\n- `inafecto`: inafecto al IGV."
          },
          "product_code": {
            "type": [
              "null",
              "string"
            ],
            "description": "Código interno del integrador, de hasta 30 caracteres (`422 field_too_long`), sin saltos de línea ni tabuladores (`422 field_invalid_characters`)."
          }
        },
        "description": "Línea del comprobante. Lleva exactamente uno entre `unit_price` y `unit_value`: ninguno responde `422 unit_amount_required` y ambos, `422 unit_amount_ambiguous`. Un ítem que suma 0.00 responde `422 amount_invalid`. Una factura también responde `422 amount_invalid` si sus importes no cuadran con la tolerancia de SUNAT; una boleta en ese caso se emite, porque SUNAT solo la observa."
      },
      "DocumentLinksDto": {
        "required": [
          "pdf",
          "xml",
          "cdr"
        ],
        "type": "object",
        "properties": {
          "pdf": {
            "type": [
              "null",
              "string"
            ],
            "description": "Ruta del PDF."
          },
          "xml": {
            "type": [
              "null",
              "string"
            ],
            "description": "Ruta del XML firmado."
          },
          "cdr": {
            "type": [
              "null",
              "string"
            ],
            "description": "Ruta del CDR; nula hasta que SUNAT responde, y en una boleta confirmada con una revisión manual de su resumen, que no tiene CDR."
          }
        },
        "description": "Rutas relativas a esta API para descargar los archivos, con la misma clave."
      },
      "DocumentStatus": {
        "enum": [
          "issued",
          "void_requested",
          "voided",
          "expired"
        ],
        "description": "Estado interno del documento.\n\n- `issued`: emitido, numerado y con XML firmado. Es el estado inicial y el habitual.\n- `void_requested`: se pidió anularlo y se espera que SUNAT acepte la baja.\n- `voided`: SUNAT aceptó la anulación. Es un estado final.\n- `expired`: se confirmó que no hubo un envío válido dentro del plazo."
      },
      "DocumentSunatDto": {
        "required": [
          "response_code",
          "description",
          "notes",
          "deadline_at",
          "submitted_at",
          "accepted_at",
          "reconciliation_required"
        ],
        "type": "object",
        "properties": {
          "response_code": {
            "type": [
              "null",
              "string"
            ],
            "description": "Código de respuesta de SUNAT; nulo hasta que responde."
          },
          "description": {
            "type": [
              "null",
              "string"
            ],
            "description": "Descripción de la respuesta de SUNAT; nula hasta que responde."
          },
          "notes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Observaciones de SUNAT."
          },
          "deadline_at": {
            "type": "string",
            "description": "Fin del plazo de envío: la fecha de emisión más 3 días en facturas y sus notas, y más 7 en boletas y sus notas, al final del día de Lima. No limita la llegada del CDR.",
            "format": "date-time"
          },
          "submitted_at": {
            "type": [
              "null",
              "string"
            ],
            "description": "Envío a SUNAT; nulo si aún no se envió. Timestamp RFC 3339 en UTC, con seis decimales.",
            "format": "date-time"
          },
          "accepted_at": {
            "type": [
              "null",
              "string"
            ],
            "description": "Aceptación de SUNAT; nula si aún no se aceptó. Timestamp RFC 3339 en UTC, con seis decimales.",
            "format": "date-time"
          },
          "reconciliation_required": {
            "type": "boolean",
            "description": "`true` si hay un envío con resultado desconocido y se está recuperando el CDR o el ticket. No reemitas mientras dure."
          }
        },
        "description": "Resultado del envío a SUNAT."
      },
      "DocumentTotalsDto": {
        "required": [
          "taxable",
          "exempt",
          "unaffected",
          "discount",
          "igv",
          "total",
          "amount_in_words"
        ],
        "type": "object",
        "properties": {
          "taxable": {
            "type": "number",
            "description": "Total de operaciones gravadas, sin IGV."
          },
          "exempt": {
            "type": "number",
            "description": "Total de operaciones exoneradas."
          },
          "unaffected": {
            "type": "number",
            "description": "Total de operaciones inafectas."
          },
          "discount": {
            "type": "number",
            "description": "Total de descuentos; hoy siempre `0.00`."
          },
          "igv": {
            "type": "number",
            "description": "IGV total."
          },
          "total": {
            "type": "number",
            "description": "Importe total con IGV."
          },
          "amount_in_words": {
            "type": "string",
            "description": "Importe total en letras."
          }
        },
        "description": "Totales del comprobante en soles, con 2 decimales."
      },
      "DocumentType": {
        "enum": [
          "factura",
          "boleta",
          "nota_credito",
          "nota_debito"
        ],
        "description": "Tipo de comprobante.\n\n- `factura`: factura electrónica.\n- `boleta`: boleta de venta electrónica.\n- `nota_credito`: nota de crédito sobre una factura o una boleta.\n- `nota_debito`: nota de débito sobre una factura o una boleta."
      },
      "EnvironmentsReadyDto": {
        "required": [
          "test",
          "live"
        ],
        "type": "object",
        "properties": {
          "test": {
            "type": "boolean",
            "description": "Verdadero salvo si la empresa está suspendida."
          },
          "live": {
            "type": "boolean",
            "description": "Verdadero solo cuando la empresa está `ready` y la cuenta está activada para `live`."
          }
        },
        "description": "Si la empresa está habilitada en cada ambiente. No comprueba la salud del certificado ni de las credenciales."
      },
      "ErrorBody": {
        "required": [
          "type",
          "code",
          "message",
          "request_id"
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Familia del error, como `validation_error`, `conflict` o `unavailable`."
          },
          "code": {
            "type": "string",
            "description": "Código estable, para programar contra él."
          },
          "message": {
            "type": "string",
            "description": "Mensaje en español, apto para mostrar a un operador. Puede cambiar: no se programa contra él."
          },
          "param": {
            "type": [
              "null",
              "string"
            ],
            "description": "Ruta del campo en el JSON, con índices entre corchetes, como `items[2].unit_price`. Solo cuando el error apunta a un campo."
          },
          "request_id": {
            "type": "string",
            "description": "Identificador de la solicitud, el mismo de `X-Request-Id`. Inclúyelo al escribir a soporte."
          },
          "document_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Documento con el que choca la solicitud. Solo en `external_id_conflict` y `document_already_replaced`.",
            "format": "uuid"
          }
        },
        "description": "El error principal."
      },
      "ErrorItem": {
        "required": [
          "code",
          "message"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Código estable, para programar contra él."
          },
          "message": {
            "type": "string",
            "description": "Mensaje en español, apto para mostrar a un operador."
          },
          "param": {
            "type": [
              "null",
              "string"
            ],
            "description": "Ruta del campo en el JSON, si el error apunta a uno."
          }
        },
        "description": "Uno de los problemas de la solicitud."
      },
      "ErrorResponse": {
        "required": [
          "error"
        ],
        "type": "object",
        "properties": {
          "error": {
            "description": "El error principal.",
            "$ref": "#/components/schemas/ErrorBody"
          },
          "errors": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/ErrorItem"
            },
            "description": "Todos los problemas. Solo aparece cuando hay varios."
          }
        },
        "description": "Formato único de los errores de la API."
      },
      "FiscalEnvironment": {
        "enum": [
          "test",
          "live"
        ],
        "description": "Ambiente, que viene dado por la API key.\n\n- `test`: SUNAT beta, sin valor fiscal.\n- `live`: SUNAT producción."
      },
      "InstallmentInput": {
        "required": [
          "amount",
          "due_date"
        ],
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Monto de la cuota en soles, mayor que cero, con hasta 12 enteros y 2 decimales (`422 installment_amount_invalid`)."
          },
          "due_date": {
            "type": "string",
            "description": "Fecha de pago de la cuota, posterior a la fecha de emisión (`422 installment_due_date_invalid`).",
            "format": "date"
          }
        },
        "description": "Cuota de una factura al crédito."
      },
      "IntegrationCompanyDto": {
        "required": [
          "id",
          "ruc",
          "legal_name",
          "trade_name",
          "status",
          "environments_ready",
          "series"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "UUID de la empresa: es el `company_id` de la emisión.",
            "format": "uuid"
          },
          "ruc": {
            "type": "string",
            "description": "RUC de la empresa."
          },
          "legal_name": {
            "type": "string",
            "description": "Razón social."
          },
          "trade_name": {
            "type": [
              "null",
              "string"
            ],
            "description": "Nombre comercial; nulo si no tiene."
          },
          "status": {
            "description": "Estado de la empresa.",
            "$ref": "#/components/schemas/CompanyStatus"
          },
          "environments_ready": {
            "description": "Habilitación por ambiente.",
            "$ref": "#/components/schemas/EnvironmentsReadyDto"
          },
          "series": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegrationSeriesDto"
            },
            "description": "Series activas en el ambiente de la clave, ordenadas por tipo y código. Vacía si no tiene."
          }
        },
        "description": "Empresa emisora del tenant."
      },
      "IntegrationSeriesDto": {
        "required": [
          "id",
          "establishment_id",
          "environment",
          "document_type",
          "code",
          "is_default"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "UUID de la serie.",
            "format": "uuid"
          },
          "establishment_id": {
            "type": "string",
            "description": "UUID del establecimiento de la serie.",
            "format": "uuid"
          },
          "environment": {
            "description": "Ambiente de la serie.",
            "$ref": "#/components/schemas/FiscalEnvironment"
          },
          "document_type": {
            "description": "Tipo de comprobante que emite.",
            "$ref": "#/components/schemas/SeriesDocumentType"
          },
          "code": {
            "type": "string",
            "description": "Código de la serie, como `B001`: es el `series` de la emisión."
          },
          "is_default": {
            "type": "boolean",
            "description": "Si es la serie por defecto de su tipo en ese establecimiento y ambiente."
          }
        },
        "description": "Serie activa de la empresa en el ambiente de la clave."
      },
      "IssueCreditNoteCommand": {
        "required": [
          "reason",
          "reason_code"
        ],
        "type": "object",
        "properties": {
          "reason_code": {
            "enum": [
              "anulacion_operacion",
              "anulacion_error_ruc",
              "correccion_descripcion",
              "descuento_global",
              "descuento_item",
              "devolucion_total",
              "devolucion_item",
              "bonificacion",
              "disminucion_valor",
              "otros"
            ],
            "type": "string",
            "description": "Motivo de la nota. Otro valor responde `422 credit_note_reason_invalid`, y uno que no se admite sobre una boleta, `422 credit_note_reason_not_allowed`.\n\n- `anulacion_operacion`: anulación de la operación.\n- `anulacion_error_ruc`: anulación por error en el RUC.\n- `correccion_descripcion`: corrección por error en la descripción.\n- `descuento_global`: descuento global. No se admite sobre una boleta.\n- `descuento_item`: descuento por ítem. No se admite sobre una boleta.\n- `devolucion_total`: devolución total.\n- `devolucion_item`: devolución por ítem.\n- `bonificacion`: bonificación. No se admite sobre una boleta.\n- `disminucion_valor`: disminución en el valor.\n- `otros`: otros conceptos."
          },
          "reason": {
            "type": "string",
            "description": "Descripción libre del motivo, de hasta 250 caracteres, sin saltos de línea ni tabuladores (`422 field_required`, `422 field_too_long`, `422 field_invalid_characters`)."
          },
          "items": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/DocumentItemInput"
            },
            "description": "Ítems de la nota, como en la emisión. Si se omite, la nota cubre el total del afectado con sus mismos ítems."
          },
          "series": {
            "type": [
              "null",
              "string"
            ],
            "description": "Serie de notas de crédito, con la letra del afectado (`422 credit_note_series_mismatch`). Por defecto, la serie por defecto del establecimiento del afectado o, si esa no tiene su letra, la única serie activa de notas que la tenga. Una que no existe o no es del establecimiento responde `422 series_not_found`; una de otro tipo, `422 series_type_mismatch`; una cerrada, `422 series_closed`; y una que llegó a su último número, `422 series_exhausted`."
          },
          "issue_date": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha de emisión; por defecto hoy en Lima. No anterior a la del afectado (`422 credit_note_before_affected`). No futura, y hasta hoy menos 3 días si el afectado es una factura y menos 7 si es una boleta (`422 issue_date_out_of_window`).",
            "format": "date"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ],
            "description": "Observación visible en el PDF, de hasta 500 caracteres, sin saltos de línea ni tabuladores (`422 field_too_long`, `422 field_invalid_characters`)."
          },
          "metadata": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/JsonElement"
              }
            ],
            "description": "Objeto JSON libre de hasta 4 KB. Se devuelve el mismo objeto, aunque el orden de sus claves y los espacios pueden cambiar. Otro valor, o uno con U+0000, responde `422 metadata_invalid`."
          },
          "external_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identificador del integrador, de hasta 64 caracteres (`422 field_too_long`), sin saltos de línea ni tabuladores (`422 field_invalid_characters`), único por empresa y ambiente entre los documentos no rechazados. Repetirlo responde `409 external_id_conflict` con el `document_id` del existente; tras un rechazo se puede reutilizar para la reemisión."
          }
        },
        "description": "Nota de crédito sobre el documento de la ruta. Una nota no lleva detracción, aunque la lleve su afectado (`422 detraction_not_allowed`), ni forma de pago, aunque su afectado sea al crédito (`422 payment_terms_not_supported`)."
      },
      "IssueDebitNoteCommand": {
        "required": [
          "items",
          "reason",
          "reason_code"
        ],
        "type": "object",
        "properties": {
          "reason_code": {
            "enum": [
              "intereses_mora",
              "aumento_valor",
              "penalidades"
            ],
            "type": "string",
            "description": "Motivo de la nota. Otro valor responde `422 debit_note_reason_invalid`.\n\n- `intereses_mora`: intereses por mora.\n- `aumento_valor`: aumento en el valor.\n- `penalidades`: penalidades. La nota es inafecta: un ítem sin `tax_affectation` va inafecto y uno gravado o exonerado responde `422 debit_note_penalty_not_inafecto`."
          },
          "reason": {
            "type": "string",
            "description": "Descripción libre del motivo, de hasta 250 caracteres, sin saltos de línea ni tabuladores (`422 field_required`, `422 field_too_long`, `422 field_invalid_characters`)."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentItemInput"
            },
            "description": "Lo que se cobra de más, como en la emisión, con al menos un ítem (`422 items_required`). La afectación de cada ítem se indica como en la emisión y la tasa del IGV es la del afectado."
          },
          "series": {
            "type": [
              "null",
              "string"
            ],
            "description": "Serie de notas de débito, con la letra del afectado (`422 debit_note_series_mismatch`). Por defecto, la serie por defecto del establecimiento del afectado o, si esa no tiene su letra, la única serie activa de notas de débito que la tenga. Una que no existe o no es del establecimiento responde `422 series_not_found`; una de otro tipo, `422 series_type_mismatch`; una cerrada, `422 series_closed`; y una que llegó a su último número, `422 series_exhausted`."
          },
          "issue_date": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha de emisión; por defecto hoy en Lima. No anterior a la del afectado (`422 debit_note_before_affected`). No futura, y hasta hoy menos 3 días si el afectado es una factura y menos 7 si es una boleta (`422 issue_date_out_of_window`).",
            "format": "date"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ],
            "description": "Observación visible en el PDF, de hasta 500 caracteres, sin saltos de línea ni tabuladores (`422 field_too_long`, `422 field_invalid_characters`)."
          },
          "metadata": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/JsonElement"
              }
            ],
            "description": "Objeto JSON libre de hasta 4 KB. Se devuelve el mismo objeto, aunque el orden de sus claves y los espacios pueden cambiar. Otro valor, o uno con U+0000, responde `422 metadata_invalid`."
          },
          "external_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identificador del integrador, de hasta 64 caracteres (`422 field_too_long`), sin saltos de línea ni tabuladores (`422 field_invalid_characters`), único por empresa y ambiente entre los documentos no rechazados. Repetirlo responde `409 external_id_conflict` con el `document_id` del existente; tras un rechazo se puede reutilizar para la reemisión."
          }
        },
        "description": "Nota de débito sobre el documento de la ruta. Una nota no lleva detracción, aunque la lleve su afectado (`422 detraction_not_allowed`), ni forma de pago (`422 payment_terms_not_supported`)."
      },
      "IssueDocumentCommand": {
        "required": [
          "items",
          "type"
        ],
        "type": "object",
        "properties": {
          "type": {
            "enum": [
              "factura",
              "boleta"
            ],
            "type": "string",
            "description": "Tipo de comprobante. Otro valor responde `422 document_type_invalid`.\n\n- `factura`: factura electrónica.\n- `boleta`: boleta de venta electrónica."
          },
          "company_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "UUID de la empresa emisora; sale de `GET /v1/companies`. Se puede omitir si la clave tiene empresa por defecto (`422 company_required` si no). Una que no existe en la cuenta responde `422 company_not_found`. Una empresa suspendida, o en `live` una que no está `ready`, responde `422 company_not_ready`.",
            "format": "uuid"
          },
          "establishment_code": {
            "type": [
              "null",
              "string"
            ],
            "description": "Código del establecimiento. Normalmente no hace falta, porque la serie ya fija el establecimiento, y `GET /v1/companies` no devuelve este código. Por defecto, el de `series` si se envió; si no, el principal. Uno que no existe responde `422 establishment_not_found`."
          },
          "series": {
            "type": [
              "null",
              "string"
            ],
            "description": "Serie, como `B001`. Por defecto, la serie por defecto del tipo en ese establecimiento y ambiente. No distingue mayúsculas. Una que no existe o no es del establecimiento responde `422 series_not_found`; una de otro tipo, `422 series_type_mismatch`; una cerrada, `422 series_closed`; y una que llegó a su último número, `422 series_exhausted`."
          },
          "issue_date": {
            "type": [
              "null",
              "string"
            ],
            "description": "Fecha de emisión; por defecto hoy en Lima. No futura, y hasta hoy menos 3 días en factura y menos 7 en boleta (`422 issue_date_out_of_window`).",
            "format": "date"
          },
          "currency": {
            "enum": [
              "PEN"
            ],
            "type": [
              "null",
              "string"
            ],
            "description": "Moneda; por defecto `PEN`, la única admitida (`422 currency_not_supported`).\n\n- `PEN`: soles."
          },
          "customer": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/DocumentCustomerInput"
              }
            ],
            "description": "Cliente. Obligatorio en una factura y en una boleta de más de S/ 700 con IGV."
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentItemInput"
            },
            "description": "Líneas del comprobante, de 1 a 200 (`422 items_required`, `422 items_too_many`)."
          },
          "notes": {
            "type": [
              "null",
              "string"
            ],
            "description": "Observación visible en el PDF, de hasta 500 caracteres, sin saltos de línea ni tabuladores (`422 field_too_long`, `422 field_invalid_characters`)."
          },
          "payment_terms": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PaymentTermsInput"
              }
            ],
            "description": "Forma de pago; por defecto al contado."
          },
          "detraction": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/DetractionInput"
              }
            ],
            "description": "Detracción, solo en facturas sujetas."
          },
          "metadata": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/JsonElement"
              }
            ],
            "description": "Objeto JSON libre de hasta 4 KB. Se devuelve el mismo objeto, aunque el orden de sus claves y los espacios pueden cambiar. Otro valor, o uno con U+0000, responde `422 metadata_invalid`."
          },
          "external_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Identificador del integrador, de hasta 64 caracteres (`422 field_too_long`), sin saltos de línea ni tabuladores (`422 field_invalid_characters`), único por empresa y ambiente entre los documentos no rechazados. Repetirlo responde `409 external_id_conflict` con el `document_id` del existente; tras un rechazo se puede reutilizar para la reemisión."
          },
          "replaces_document_id": {
            "type": [
              "null",
              "string"
            ],
            "description": "Documento rechazado que este reemplaza, de la misma empresa y ambiente (`422 replaced_document_not_rejected`). Cada rechazado se reemplaza una sola vez: otro intento responde `409 document_already_replaced` con el `document_id` del reemplazo.",
            "format": "uuid"
          }
        },
        "description": "Boleta o factura por emitir. Las notas de crédito y de débito tienen su propia operación."
      },
      "ItemTaxAffectation": {
        "enum": [
          "gravado",
          "exonerado",
          "inafecto"
        ],
        "description": "Afectación al IGV de la línea.\n\n- `gravado`: paga IGV.\n- `exonerado`: exonerado de IGV.\n- `inafecto`: inafecto al IGV."
      },
      "JsonElement": {
        "type": "object",
        "description": "Objeto JSON libre."
      },
      "PageOfDocumentDto": {
        "required": [
          "data",
          "next_cursor"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentDto"
            },
            "description": "Documentos de la página, sin `items` ni `qr_image`."
          },
          "next_cursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cursor de la página siguiente, para pasarlo en `cursor`; nulo en la última página."
          }
        },
        "description": "Una página de documentos."
      },
      "PageOfIntegrationCompanyDto": {
        "required": [
          "data",
          "next_cursor"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegrationCompanyDto"
            },
            "description": "Empresas de la página."
          },
          "next_cursor": {
            "type": [
              "null",
              "string"
            ],
            "description": "Cursor de la página siguiente, para pasarlo en `cursor`; nulo en la última página."
          }
        },
        "description": "Una página de empresas."
      },
      "PaymentTermsInput": {
        "required": [
          "type"
        ],
        "type": "object",
        "properties": {
          "type": {
            "enum": [
              "contado",
              "credito"
            ],
            "type": "string",
            "description": "Tipo de pago. Otro valor responde `422 payment_terms_not_supported`.\n\n- `contado`: pago al contado, sin `installments` (`422 installments_not_allowed`).\n- `credito`: el total o una parte se cobra después de la emisión. Solo en facturas: una boleta responde `422 payment_terms_not_supported`."
          },
          "installments": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/InstallmentInput"
            },
            "description": "Cuotas de una factura al crédito, de 1 a 999 (`422 installments_required`, `422 installments_too_many`), cada una con `amount` y `due_date` (`422 field_required`). Su suma es el monto neto pendiente y no supera el total menos la detracción, si la lleva (`422 installments_exceed_total`); puede ser menor si el cliente retiene una parte."
          }
        },
        "description": "Forma de pago."
      },
      "RequestVoidCommand": {
        "required": [
          "reason"
        ],
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Motivo de la baja, de 3 a 100 caracteres, sin saltos de línea ni tabuladores (`422 field_required`, `422 field_too_short`, `422 field_too_long`, `422 field_invalid_characters`)."
          }
        },
        "description": "Solicitud de baja."
      },
      "SendDocumentEmailCommand": {
        "type": "object",
        "properties": {
          "email": {
            "type": [
              "null",
              "string"
            ],
            "description": "Correo de destino. Si se omite, va al correo del cliente del documento."
          }
        },
        "description": "Envío del documento por correo. El cuerpo se puede omitir."
      },
      "SeriesDocumentType": {
        "enum": [
          "factura",
          "boleta",
          "nota_credito",
          "nota_debito"
        ],
        "description": "Tipo de comprobante de la serie.\n\n- `factura`: factura electrónica.\n- `boleta`: boleta de venta electrónica.\n- `nota_credito`: nota de crédito sobre una factura o una boleta.\n- `nota_debito`: nota de débito sobre una factura o una boleta."
      },
      "Stream": {
        "type": "string",
        "description": "El contenido del archivo.",
        "format": "binary"
      },
      "SunatStatus": {
        "enum": [
          "pending",
          "submitted",
          "accepted",
          "accepted_with_observations",
          "rejected",
          "deadline_missed"
        ],
        "description": "Estado fiscal del documento.\n\n- `pending`: pendiente de informar a SUNAT: una factura y sus notas se envían solas, y una boleta y sus notas van en el resumen diario. Se puede entregar al cliente aclarando que falta la validación.\n- `submitted`: enviado, o conciliando un resultado desconocido. No se reemite mientras el resultado sea incierto.\n- `accepted`: aceptado por SUNAT.\n- `accepted_with_observations`: aceptado con observaciones, que están en `sunat.notes`.\n- `rejected`: rechazado; el motivo está en `sunat.description` y el número no se reutiliza. Una factura o una boleta se corrige emitiendo otro documento con `replaces_document_id`. Una nota de crédito se corrige emitiendo otra nota, porque `replaces_document_id` no aplica y la rechazada no cuenta en el saldo del afectado.\n- `deadline_missed`: se confirmó que no hubo un envío válido en plazo. Contacta a soporte antes de pedir una baja o emitir otro documento."
      }
    },
    "headers": {
      "X-Request-Id": {
        "description": "El del cliente si tiene de 1 a 128 caracteres `[A-Za-z0-9._-]`; si no, uno generado. Es el `request_id` de los errores.",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit-Limit": {
        "description": "Solicitudes admitidas en la ventana de un minuto, de la clave o de la IP.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Remaining": {
        "description": "Solicitudes que quedan en la ventana.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Reset": {
        "description": "Segundos hasta la ventana siguiente.",
        "schema": {
          "type": "integer"
        }
      },
      "Retry-After": {
        "description": "Segundos que conviene esperar antes de reintentar.",
        "schema": {
          "type": "integer"
        }
      },
      "Idempotent-Replayed": {
        "description": "`true` cuando la respuesta es la guardada de una solicitud anterior con la misma `Idempotency-Key`.",
        "schema": {
          "type": "string"
        }
      }
    },
    "securitySchemes": {
      "api_key": {
        "type": "http",
        "description": "API key en `Authorization: Bearer`. El prefijo `bol_test_` o `bol_live_` elige el ambiente.",
        "scheme": "bearer"
      }
    }
  },
  "security": [
    {
      "api_key": [ ]
    }
  ],
  "tags": [
    {
      "name": "Companies"
    },
    {
      "name": "Documents"
    }
  ]
}