# External API V1 Documentation

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

## Overview

Technical documentation package for self-serve 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 to a single endpoint and Invoice-Converter handles extraction, validation, and output generation. The result endpoint returns the generated file only after validation gates pass; otherwise it returns 422 VALIDATION_FAILED.

> **Status: self-serve**: Base path: /api/v1. Last synchronized 2026-05-22.

## Key capabilities

- Single endpoint for PDF-to-XML conversion
- AI-powered invoice data extraction
- Automated EN 16931 and KoSIT validation
- XRechnung, ZUGFeRD, UBL, and CII output formats
- Async processing with polling - small invoices 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)
- [API Playground](/developer-api/playground)

## Quickstart

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

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

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

### GET /api/v1/tasks/{task_id}/result (In development)
Download conversion result

## Request closed beta access

- Create an account and open your profile.
- Buy prepaid API credits or use an Enterprise plan with included API access.
- Create an 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://invoice-converter.com/api/v1`.
- Use the same production API host for all pilot traffic: `https://invoice-converter.com/api/v1`.
- Use low-volume fixture requests during onboarding; accepted conversion requests consume API credits.
- 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 `2-5 seconds`: `GET /api/v1/tasks/{task_id}` until status is `completed` or `failed`.
- Download: `GET /api/v1/tasks/{task_id}/result` and store `X-Correlation-ID` plus `X-Validation-Proof-Id` when present.
- For ZUGFeRD PDF output, send `format=ZUGFERD`; the result endpoint defaults to the hybrid PDF.

## Common payload examples

- `XRECHNUNG`: send `format=XRECHNUNG`; this is the default when format is omitted.
- `ZUGFERD`: send `format=ZUGFERD` for an EN16931 ZUGFeRD/Factur-X hybrid PDF.
- `UBL`: send `format=UBL` for EN16931 UBL XML.
- `CII`: send `format=CII` for EN16931 CII XML.

## Required request headers

- Authorization: Bearer <api_key>

## Auth rules

API access is self-serve. Create API keys from your profile, use them as Bearer tokens, and buy prepaid API credits for conversion automation.

- Keys are tenant-scoped and use the `icp_` prefix.
- Create, rotate, and revoke API keys from your profile when External 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 (In development)
Upload a PDF invoice and start asynchronous conversion. Returns a task_id for polling. Request: multipart/form-data. Response: 202 Accepted.

### GET /api/v1/tasks/{task_id} (In development)
Poll the current status of a conversion task. Returns pending, processing, completed, or failed. When failed, the response includes an error field with the failure reason. Request: none (GET). Response: 200 OK.

### GET /api/v1/tasks/{task_id}/result (In development)
Download the generated file. ZUGFERD tasks default to an EN16931 ZUGFeRD/Factur-X hybrid PDF; other formats default to XML. Repeated downloads may be served from cached generated artifacts. If blocking validation issues remain, this endpoint returns 422 VALIDATION_FAILED and no file body. Request: none (GET). 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 | EN16931 hybrid PDF/A-3 by default; CII XML with download=xml | ZUGFeRD 2.4 / Factur-X 1.08 | application/pdf or application/xml | .pdf / .xml |
| 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-05-08
Added prepaid External API credits for non-Enterprise tenants. Documented 402 INSUFFICIENT_API_CREDITS for tenants without Enterprise billing or prepaid credits. Confirmed idempotent replays do not consume additional API credits. Simplified conversion requests to file plus format; extraction tuning is managed server-side.

### 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 | Buy at least 10 prepaid API credits or use Enterprise 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 |
| 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 |
| 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 |
| PROFILE_MISMATCH | 422 | No | Invoice CustomizationID conflicts with the selected public format |
| 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`.
- 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.

## Rate & payload limits

Per-key rate limits and payload size constraints are enforced for all API calls. Denied requests do not consume quota.

- Endpoint-aware quotas are cost-weighted. Convert uses the baseline plan quota (default `30/min` and `500/hour`), while polling endpoints use lower weighted quotas.
- Read effective limits from `X-RateLimit-Limit-Minute` and `X-RateLimit-Limit-Hour` on responses.
- PDF upload max size: `20 MB`
- 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`, `403`, `409`, `413`).

## 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.
- Target first response: 1 business day.

## 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)%2520%0D%0A2)%2520%0D%0A3)%2520%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.
