Reference

Error Handling

Understand API errors and learn how to handle them in your application. All errors follow a consistent format with helpful details.

Error Response Format

All API errors are returned in the following JSON format:

json
1{
2 "error": "VALIDATION_FAILED",
3 "message": "Die Rechnung entspricht nicht dem XRechnung 3.0.2 Schema"
4}

error

Machine-readable error code for programmatic handling

message

Human-readable error description

HTTP Status Codes

400
Bad Request

Invalid request data (JSON, XML, missing required fields)

401
Unauthorized

Missing or invalid API key

402
Payment Required

Quota exhausted, upgrade required

403
Forbidden

API key has no permission for this resource

404
Not Found

Resource (e.g. invoice) not found

422
Unprocessable Entity

Semantic error (e.g. invalid VAT ID)

429
Too Many Requests

Rate limit reached

500
Internal Server Error

Server error, please try again

503
Service Unavailable

Service temporarily unavailable (maintenance)

API Error Codes

CodeHTTPDescriptionSolution
INVALID_REQUEST400Request body is not valid JSON or XMLCheck the syntax of your request body
MISSING_FIELD400A required field is missing from the requestAdd the missing field (see details.field)
INVALID_FORMAT400The specified format is not supportedUse: xrechnung-3.0, zugferd-2.1, etc.
VALIDATION_FAILED400E-invoice does not match the schemaCheck the details for specific error messages
UNAUTHORIZED401API key is missing or invalidCheck the Authorization: Bearer <key> header
INVALID_API_KEY401API key does not exist or was revokedCreate a new API key in the dashboard
QUOTA_EXCEEDED402Monthly quota exhaustedUpgrade your plan or wait until the end of the month
FORBIDDEN403API key has no permissionCheck if the key is enabled for this endpoint
NOT_FOUND404Resource not foundCheck the ID or endpoint path
INVALID_VAT_ID422VAT ID has incorrect formatFormat: DE + 9 digits (e.g. DE123456789)
INVALID_LEITWEG422Leitweg ID has incorrect formatFormat: XXX-XXXXX-XX (e.g. 991-12345-67)
INVALID_IBAN422IBAN is invalidCheck the IBAN checksum
CALCULATION_MISMATCH422Totals do not matchCheck: Net + VAT = Gross
RATE_LIMITED429Too many requestsWait and try again later
INTERNAL_ERROR500Internal server errorTry again, contact support if it persists

XRechnung Validation Errors (BR-DE)

These errors come from KoSIT Schematron validation and are returned in error.details:

BR-DE-01

An invoice must contain a Leitweg ID

Field: buyer.leitweg

BR-DE-15

Seller country code must be provided

Field: seller.address.country

BR-DE-17

Seller VAT ID or tax number is missing

Field: seller.vatId / seller.taxNumber

BR-16

Invoice total does not match line items

Field: totals / items

BR-CO-10

Sum of line items does not equal invoice net amount

Field: items[].quantity * items[].unitPrice

BR-CO-13

VAT amount does not match tax rate

Field: vat calculation

BR-S-08

Invalid VAT category code

Field: items[].vat

BR-CL-10

Invalid currency code

Field: currency

Full list: KoSIT XRechnung Specification

Retry Strategy

Implement retries for temporary errors (429, 5xx):

typescript
1async function createInvoice(data, retries = 3) {
2 for (let i = 0; i < retries; i++) {
3 try {
4 const response = await fetch('https://service.invoice-api.xhub.io/api/v1/invoice/DE/XRECHNUNG/generate', {
5 method: 'POST',
6 headers: {
7 'Authorization': 'Bearer sk_live_...',
8 'Content-Type': 'application/json'
9 },
10 body: JSON.stringify(data)
11 });
12 
13 if (response.status === 429) {
14 // Rate limited - wait and retry
15 const retryAfter = response.headers.get('Retry-After') || 60;
16 await new Promise(r => setTimeout(r, retryAfter * 1000));
17 continue;
18 }
19 
20 if (response.status >= 500) {
21 // Server error - retry with exponential backoff
22 await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
23 continue;
24 }
25 
26 const result = await response.json();
27 
28 if (!response.ok) {
29 // Client error - don't retry, handle the error
30 throw new Error(result.message);
31 }
32 
33 return result;
34 } catch (error) {
35 if (i === retries - 1) throw error;
36 }
37 }
38}

Best Practices

Log Errors

Always log the requestId. This helps us trace requests for support inquiries.

Retry Only on 5xx/429

Client errors (4xx) won't be fixed by retries. Only retry on server or rate limit errors.

Exponential Backoff

For retries: double the wait time after each failed attempt (1s, 2s, 4s, ...) to avoid overloading the server.

Retry-After Header

On 429, the header Retry-After contains the recommended wait time in seconds.

Support

For recurring errors or unclear error messages, contact us at support@xhub.io with the requestId.