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:
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
Invalid request data (JSON, XML, missing required fields)
Missing or invalid API key
Quota exhausted, upgrade required
API key has no permission for this resource
Resource (e.g. invoice) not found
Semantic error (e.g. invalid VAT ID)
Rate limit reached
Server error, please try again
Service temporarily unavailable (maintenance)
API Error Codes
| Code | HTTP | Description | Solution |
|---|---|---|---|
INVALID_REQUEST | 400 | Request body is not valid JSON or XML | Check the syntax of your request body |
MISSING_FIELD | 400 | A required field is missing from the request | Add the missing field (see details.field) |
INVALID_FORMAT | 400 | The specified format is not supported | Use: xrechnung-3.0, zugferd-2.1, etc. |
VALIDATION_FAILED | 400 | E-invoice does not match the schema | Check the details for specific error messages |
UNAUTHORIZED | 401 | API key is missing or invalid | Check the Authorization: Bearer <key> header |
INVALID_API_KEY | 401 | API key does not exist or was revoked | Create a new API key in the dashboard |
QUOTA_EXCEEDED | 402 | Monthly quota exhausted | Upgrade your plan or wait until the end of the month |
FORBIDDEN | 403 | API key has no permission | Check if the key is enabled for this endpoint |
NOT_FOUND | 404 | Resource not found | Check the ID or endpoint path |
INVALID_VAT_ID | 422 | VAT ID has incorrect format | Format: DE + 9 digits (e.g. DE123456789) |
INVALID_LEITWEG | 422 | Leitweg ID has incorrect format | Format: XXX-XXXXX-XX (e.g. 991-12345-67) |
INVALID_IBAN | 422 | IBAN is invalid | Check the IBAN checksum |
CALCULATION_MISMATCH | 422 | Totals do not match | Check: Net + VAT = Gross |
RATE_LIMITED | 429 | Too many requests | Wait and try again later |
INTERNAL_ERROR | 500 | Internal server error | Try 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-01An invoice must contain a Leitweg ID
Field: buyer.leitweg
BR-DE-15Seller country code must be provided
Field: seller.address.country
BR-DE-17Seller VAT ID or tax number is missing
Field: seller.vatId / seller.taxNumber
BR-16Invoice total does not match line items
Field: totals / items
BR-CO-10Sum of line items does not equal invoice net amount
Field: items[].quantity * items[].unitPrice
BR-CO-13VAT amount does not match tax rate
Field: vat calculation
BR-S-08Invalid VAT category code
Field: items[].vat
BR-CL-10Invalid currency code
Field: currency
Full list: KoSIT XRechnung Specification
Retry Strategy
Implement retries for temporary errors (429, 5xx):
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 retry15 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 backoff22 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 error30 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.