# External API V1 Documentation

Technical documentation package for approved API implementation and review. This page summarizes the externally exposed API contract, access model, and integration constraints.

## Overview

Technical documentation package for approved API implementation and review. This page summarizes the externally exposed API contract, access model, and integration constraints.

The API accepts multipart uploads, returns JSON responses, and uses standard HTTP status codes and Bearer authentication. Submit a PDF invoice, wait for asynchronous processing, and then fetch the generated result.

Send a PDF invoice or structured invoice data to a conversion endpoint. Invoice-Converter starts one async task for extraction, validation, and artifact generation. The result endpoint returns a file only when the requested artifact is validated, checked, and ready; while processing it returns 202 TASK_NOT_READY, and blocking validation issues return 422 VALIDATION_FAILED.

> **Status: gated access**: Base path: /api/v1. Last synchronized 2026-06-29.

## Key capabilities

- Upload endpoints for PDF invoices and structured invoice data
- AI-powered invoice data extraction
- Automated EN 16931 and KoSIT validation
- XRechnung, ZUGFeRD, EN16931, UBL, and CII output formats
- Async processing with polling; small invoices often take around 30 seconds, larger invoices up to 1-2 minutes
- Idempotent writes for safe retries

## Delivery Artifacts

Download machine-readable integration artifacts for the Developer API.

- [OpenAPI JSON](/developer-api/v1/openapi.json)
- [Postman collection](/developer-api/v1/postman.json)

## Quickstart

Three API calls complete a conversion. The convert endpoint is served at /api/v1 and requires authentication.

### POST /api/v1/invoices:convert (Live)
Convert PDF to structured e-invoice

### POST /api/v1/invoices:convert-structured (Live)
Convert structured data

### GET /api/v1/tasks/{task_id} (Live)
Poll task status

## Get API access

- Create an account and request API access.
- Use prepaid API credits for approved testing or Enterprise order-form billing for production use.
- After approval, create a live API key from the API access section.
- Run the first request with server-side credentials, then monitor usage and rotate keys from your profile.

## Base URL and API keys

- Production base URL: `https://www.invoice-converter.com/api/v1`.
- Live keys use the production host and the `icp_...` prefix.
- Run onboarding and validation requests with approved live keys before sending production volume.
- Treat keys as server-side secrets. Do not embed them in browser or mobile clients.

## First successful request

Use this sequence as the minimum happy path after creating an API key.

- Upload: `POST /api/v1/invoices:convert` with `Authorization`, `Idempotency-Key`, `file=@invoice.pdf`, and `format=XRECHNUNG`.
- Poll every `10-15 seconds`: `GET /api/v1/tasks/{task_id}` until status is `completed` or `failed`.
- Download: `GET /api/v1/tasks/{task_id}/result?download=xml` and store `X-Correlation-ID` for support tracing.
- For ZUGFeRD PDF output, request `format=ZUGFERD` on convert and `download=pdf` on result.
- For structured input, call `POST /api/v1/invoices:convert-structured` with `pdf_file=@invoice.pdf`, `data_file=@invoice-data.json`, and the target `format`.
- Optionally send `client_reference` or `external_invoice_id` and `source_system` for ERP reconciliation.
- For split ERP exports of one invoice, repeat `data_file`; for multiple invoices, start one task per invoice with its own idempotency key.
- Store `result_artifacts` from the status response to see whether XML/PDF artifacts are validated, cached, or still unavailable because of dependencies.

## Common payload examples

- `XRECHNUNG`: send `format=XRECHNUNG`.
- `ZUGFERD`: send `format=ZUGFERD`; use `download=pdf` on result for the hybrid PDF/A-3 output.
- `Structured input`: send `pdf_file` plus one or more `data_file` parts; accepted data formats are CSV, JSON, XML, XLSX, and TXT, with any supported target format. The data_file parts must contain all mandatory data; the PDF does not fill missing fields.
- `Multiple invoices`: submit separate convert requests and track each returned `task_id`; repeated `data_file` parts are only for split exports of the same invoice.
- `UBL`: send `format=UBL`; for deterministic integrations, set an explicit `profile` such as `PEPPOL`, `XRECHNUNG`, or `EN16931`.
- `CII`: send `format=CII`; for deterministic integrations, set an explicit `profile` such as `EN16931`.

## Required request headers

- Authorization: Bearer <api_key>

## Auth rules

API access is gated. Approved accounts can create API keys from the profile, use them as Bearer tokens, and use prepaid credits for approved testing or Enterprise order-form billing for production.

- Keys are tenant-scoped live credentials for approved accounts. The current production prefix is `icp_...`.
- Create, rotate, and revoke API keys from your profile after API access is enabled. Copy new keys immediately because plaintext keys are shown only once.
- Missing or invalid key returns `401`.
- Calls to `/api/v1` receive an `X-Correlation-ID` automatically when omitted.
- Write calls require `Idempotency-Key`; keep this value stable across retries.
- Use server-to-server integration from your backend. Browser-origin access is restricted in production.

## Idempotency contract

- Send an `Idempotency-Key` on every write call.
- Idempotency keys must match `[A-Za-z0-9._:-]+` and be at most 200 chars.
- If you provide your own key, the same key + identical payload returns the cached response.
- Same key + different payload returns `409 IDEMPOTENCY_CONFLICT`.
- Idempotency keys expire after `24 hours`.

## Endpoint Reference

All endpoints are available under /api/v1. Timeouts surface as 504 and other temporary connectivity failures as 502; correlation IDs help support trace requests end-to-end.

### POST /api/v1/invoices:convert (Live)
Upload a PDF invoice and start asynchronous conversion. Returns a task_id for polling. Request: multipart/form-data; file (binary, required) — PDF invoice file; format (string, required) — target output format; see format matrix below; profile (string, optional, recommended for deterministic integrations) — explicit compliance profile. Defaults by format; allowed values include XRECHNUNG, PEPPOL, EN16931, and supported ZUGFeRD/Factur-X profiles; jurisdiction (string, optional) — explicit ISO 3166-1 alpha-2 jurisdiction context used for validation/advisory checks; does not override profile; transaction_scope (string, optional) — explicit transaction scope context, such as B2G; applied to the queued task; delivery_channel (string, optional) — one of PEPPOL, DIRECT_XML, PORTAL, EMAIL_PDF, UNKNOWN; applied to the queued task; client_reference or external_invoice_id (string, optional) — tenant-side invoice/job reference returned on accepted uploads and task status responses; source_system (string, optional) — upstream ERP or billing system label returned on accepted uploads and task status responses. Response: 202 Accepted.

### POST /api/v1/invoices:convert-structured (Live)
Upload a carrier PDF plus CSV, JSON, XML, XLSX, or TXT invoice data and start asynchronous structured-data conversion. The data_file parts are the only semantic source; the PDF does not fill missing invoice fields. For ZUGFeRD/Factur-X it is used as the carrier PDF, and for XML-oriented outputs it is retained as the submitted PDF artifact. Use one conversion request per invoice; repeat data_file only for split ERP exports that describe the same invoice. Request: multipart/form-data; pdf_file (binary, required) — carrier PDF used for ZUGFeRD/Factur-X embedding and retained for XML-oriented outputs; data_file (binary, required, repeatable) — CSV, JSON, XML, XLSX, or TXT invoice data used as the only semantic source; .xls, PDFs, and image files are rejected as data_file; repeat for split header/line exports of the same invoice; aliases data_files and data_files[] are accepted; structured data total size — max 2 MB across all data_file parts; format (string, required) — target output format; supports XRECHNUNG, ZUGFERD, EN16931, UBL, and CII; profile (string, optional, recommended for deterministic integrations) — explicit compliance profile. Defaults by format; jurisdiction (string, optional) — explicit ISO 3166-1 alpha-2 jurisdiction context used for validation/advisory checks; does not override profile; transaction_scope (string, optional) — explicit transaction scope context, such as B2G; applied to the queued task; delivery_channel (string, optional) — one of PEPPOL, DIRECT_XML, PORTAL, EMAIL_PDF, UNKNOWN; applied to the queued task; client_reference or external_invoice_id (string, optional) — tenant-side invoice/job reference returned on accepted uploads and task status responses; source_system (string, optional) — upstream ERP or billing system label returned on accepted uploads and task status responses. Response: 202 Accepted.

### GET /api/v1/tasks/{task_id} (Live)
Poll the current status of a conversion task. Returns pending, processing, completed, or failed. Completed tasks include `result_artifacts` diagnostics so clients can see which XML/PDF artifacts are available, cached, and validation-proven. When failed, the response includes an error field with the failure reason. Request: none (GET); task_id (path, required) — UUID returned by the convert endpoint. Response: 200 OK.

### GET /api/v1/tasks/{task_id}/result (Live)
Download the generated file (XML or PDF). Result syntax matches the original task format: XRECHNUNG/EN16931/UBL return UBL XML, CII/ZUGFERD return CII XML, and ZUGFERD + download=pdf returns a hybrid PDF/A-3. For other formats, download=pdf can return a rendered PDF. Repeated downloads may be served from cached generated artifacts when validation proof is still current. While processing, this endpoint returns 202 TASK_NOT_READY; blocking validation issues return 422 VALIDATION_FAILED, retryable dependency gaps return 503, and artifact invariant failures return 500, all with no file body. Request: none (GET); task_id (path, required) — UUID returned by the convert endpoint; download (query, required) — xml or pdf. Response: 200 OK.

### GET /api/v1/tasks/{task_id}/validation-report (Live)
Download the validation report tied to the current validated result artifact. The report is available only after strict conversion has produced a cached artifact with current validation proof, and returns 404 when no report is bound to the delivered artifact. Request: none (GET); task_id (path, required) — UUID returned by the convert endpoint; download (query, optional) — html or xml. Response: 200 OK.

## Output format matrix

| Format | Syntax | Version / Profile | Content-Type | Extension |
| --- | --- | --- | --- | --- |
| XRECHNUNG | UBL 2.1 XML | XRechnung 3.0.2 | application/xml | .xml |
| ZUGFERD | CII XML (download=xml) / hybrid PDF/A-3 (download=pdf) | ZUGFeRD 2.4 / Factur-X 1.08 | application/xml or application/pdf | .xml / .pdf |
| EN16931 | UBL 2.1 XML | EN 16931 | application/xml | .xml |
| UBL | UBL 2.1 XML | OASIS UBL 2.1 | application/xml | .xml |
| CII | UN/CEFACT CII XML | D16B | application/xml | .xml |

## Changelog

Recent externally visible API changes.

### 2026-06-02
External API access is now documented as approved gated access rather than ungated key creation. Clarified that no formal SLA, service credit, or contractual penalty applies unless agreed in an order form. format is now required on both conversion endpoints; missing values return 400 FORMAT_REQUIRED and unsupported values return 422 INVALID_FORMAT. download is now required on task-result requests; missing values return 400 DOWNLOAD_FORMAT_REQUIRED and unsupported values return 400 INVALID_DOWNLOAD_FORMAT. Conversion uploads now accept client_reference/external_invoice_id and source_system for customer-side reconciliation. Accepted conversion and task-status responses now include status_url, primary_result_format, primary_result_url, and supplied reconciliation fields.

### 2026-06-01
Structured conversion now accepts all public output formats: XRECHNUNG, ZUGFeRD, EN16931, UBL, and CII. Structured conversion now accepts repeatable data_file parts plus data_files and data_files[] aliases for split ERP exports. Structured multi-file bundles must describe exactly one invoice and fail fast on conflicting or missing bundle invoice IDs. Clarified that multiple invoice documents should be submitted as separate conversion tasks, each with its own idempotency key.

### 2026-05-27
Added POST /api/v1/invoices:convert-structured for carrier-PDF plus CSV/JSON/XML/XLSX/TXT structured-data conversion across supported output formats. Documented that structured data is the only semantic source on this endpoint; the PDF is used for hybrid embedding. Updated OpenAPI and Postman artifacts for structured conversion.

### 2026-05-08
Added prepaid External API credits for non-Enterprise tenants. Documented 402 INSUFFICIENT_API_CREDITS for approved tenants without Enterprise order-form billing or prepaid credits. Confirmed idempotent replays do not consume additional API credits. Clarified that External API V1 model routing is managed server-side while profile and delivery context stay caller-controlled.

### 2026-03-06
Made task-result downloads format-faithful for CII and ZUGFERD outputs. Added cached result artifact reuse for repeated XML/PDF downloads of the same task. Aligned polling quotas with endpoint-scoped weighted rate-limit buckets.

### 2026-02-23
Added clearer, consistent API error responses across all endpoints. Expanded convert options and documented XML/PDF download behavior for task results. Improved retry safety with stricter idempotency requirements and validation. Updated OpenAPI/Postman artifacts to match current API behavior.

### 2026-02-20
Simplified status responses to status-focused output. Strengthened IndexNow submission validation and authentication checks. Hardened API access controls and request-limiting behavior in production.

## Error Contract

| Code | HTTP | Retryable | Notes |
| --- | --- | --- | --- |
| AUTHENTICATION_REQUIRED | 401 | No | Missing/empty bearer token |
| INVALID_API_KEY | 401 | No | API key not found/revoked/expired |
| INSUFFICIENT_API_CREDITS | 402 | No | Use approved prepaid testing credits or Enterprise order-form billing |
| IDEMPOTENCY_KEY_REQUIRED | 400 | No | Write endpoint called without Idempotency-Key |
| INVALID_IDEMPOTENCY_KEY | 400 | No | Idempotency key has invalid format |
| IDEMPOTENCY_CONFLICT | 409 | No | Same key used with different request hash |
| IDEMPOTENCY_IN_PROGRESS | 409 | Yes | Safe to retry later with same key/payload |
| FORMAT_REQUIRED | 400 | No | Conversion request missing required format |
| INVALID_FORMAT | 422 | No | Unsupported conversion format |
| CLIENT_REFERENCE_CONFLICT | 400 | No | client_reference and external_invoice_id differ |
| DOWNLOAD_FORMAT_REQUIRED | 400 | No | Task result request missing required download query |
| INVALID_DOWNLOAD_FORMAT | 400 | No | Task result download query must be xml or pdf |
| AUTH_SERVICE_UNAVAILABLE | 503 | Yes | Auth backend unavailable |
| RATE_LIMIT_SERVICE_UNAVAILABLE | 503 | Yes | Rate-limit backend unavailable |
| RATE_LIMITED | 429 | Yes | Respect Retry-After and quota headers |
| BAD_REQUEST | 400 | No | Invalid JSON or invalid UUID path parameter |
| PAYLOAD_TOO_LARGE | 413 | No | Over upload size limit |
| INVALID_UPLOAD | 400 | No | Upload read/parsing failure |
| UPLOAD_FAILED | 4xx/5xx | Conditional | Fix invalid request options; retry only for transient 5xx cases |
| TASK_NOT_READY | 202 | Yes | Poll again for async completion |
| VALIDATION_FAILED | 422 | No | Blocking validation issues remain; correct invoice data before retrying |
| AUTHORITATIVE_VALIDATION_UNAVAILABLE | 503 | Yes | Authoritative validation, proof persistence, or hybrid-generation dependency unavailable; retry later |
| TASK_STATUS_FAILED | 4xx/5xx | Conditional | Retry if transient service condition |
| TASK_RESULT_FAILED | 4xx/5xx | Conditional | Retry if transient service condition |
| XML_GENERATION_FAILED | 500 | Yes | Transient XML generation failure or timeout |
| PDF_GENERATION_FAILED | 500 | Yes | Transient PDF generation failure or timeout |
| ARTIFACT_GENERATION_RERUN_REQUIRED | 503 | No | Strict artifact generation failed after server-side retries; start a new conversion after the dependency recovers |
| ZUGFERD_SOURCE_PDF_INCOMPATIBLE | 422 | No | Strict hybrid PDF generation cannot embed XML into the uploaded source PDF |
| OUTPUT_PROFILE_REQUIRED | 422 | No | A generic output contract requires an explicit profile when no unambiguous default can be determined |
| OUTPUT_PROFILE_CONFLICT | 422 | No | Profile contradicts the selected output format or explicit variant |
| PROXY_ERROR | 502/504 | Yes | Temporary connectivity failure (504 for timeout) |

## Common errors and what to do

- Retry with backoff: `429`, `500`, `502`, `503`, `504`.
- Fix request or source data: `400`, `409`, `413`, `422`.
- Fix access or credentials: `401`, `403`.
- Confirm approval and prepaid testing credits or Enterprise order-form billing: `402 INSUFFICIENT_API_CREDITS`.
- Keep polling later: `202 TASK_NOT_READY`.
- For `422 VALIDATION_FAILED`, show the returned field, rule ID, and remediation to a human reviewer before retrying with corrected invoice data.
- For `503 AUTHORITATIVE_VALIDATION_UNAVAILABLE`, fetch the same task result later; no unverified artifact was delivered.

## Rate & payload limits

Per-key rate limits and payload size constraints are enforced for all API calls. Rejected conversions do not consume prepaid API credits; rate limits are calculated separately per endpoint.

- Endpoint-aware limits are cost-weighted. Both upload endpoints use the baseline quota (default `30/min` and `500/hour`); task polling is currently at least `10/min` and `120/hour`, and result downloads are currently at least `10/min` and about `134/hour` by default.
- Read effective limits from `X-RateLimit-Limit-Minute` and `X-RateLimit-Limit-Hour` on responses.
- PDF upload max size: `20 MB`
- Structured data upload max size: `2 MB` total across all `data_file` parts.
- JSON payload max size: `1 MB`
- Rate-limit responses include `Retry-After`, `X-RateLimit-Limit-Minute`, and `X-RateLimit-Limit-Hour`.

## Retry guidance

- Use exponential backoff with jitter.
- Retry only transient classes (`429`, `500`, `502`, `503`, `504`) using the same payload and idempotency key where possible.
- Do not blindly retry validation or contract errors (`400`, `401`, `402`, `403`, `409`, `413`, `422`).

## Task lifecycle & retention

- Completed and failed tasks remain available for `10 minutes` after reaching terminal state.
- Processing times out after `5 minutes` — stuck tasks are automatically marked `failed`.
- Idempotency keys expire after `24 hours`.
- Rate-limit counters reset on a rolling window.

## Support model

- Business-hours support on commercially reasonable efforts.
- No formal SLA, service credit, or response-time commitment unless agreed in an order form.

## Send Technical Feedback

Share implementation questions, risks, and required contract changes with our team.

- [Email technical feedback](mailto:contact@invoice-converter.com?subject=External%20API%20V1%20technical%20review%20feedback&body=Hello%20Invoice-Converter%20team%2C%0D%0A%0D%0AWe%20reviewed%20the%20External%20API%20V1%20documentation%20and%20have%20the%20following%20feedback%3A%0D%0A%0D%0A1)%20%0D%0A2)%20%0D%0A3)%20%0D%0A%0D%0ARegards%2C)

## Use Postman and OpenAPI

- Import the Postman collection and set `baseUrl`, `apiKey`, and a new `idempotencyKey` variable.
- Run the collection in order: convert, poll status, then fetch result.
- Use the OpenAPI JSON to generate typed clients, but keep file upload, polling, and binary result handling covered by integration tests.
- Record `X-Correlation-ID` in logs so support can trace requests end-to-end.
