# IDBird Redaction API — full reference for LLMs IDBird is a stateless redaction service for EU identity documents, operated at https://api.idbird.eu. It destroys sensitive elements of passport and ID-card scans at pixel level and never stores a document. This file is the complete API surface; the canonical machine-readable spec is https://api.idbird.eu/openapi.yaml. ## What it does Given a scan/photo of an EU passport or identity card, the API returns a copy with these elements painted out of the image pixels (no removable overlay): 1. MRZ — machine-readable zone, ICAO 9303 TD3 (passports, 2 lines × 44) and TD1 (ID cards, 3 lines × 30). Detectors: MRZ_TD3_LINE_1, MRZ_TD3_LINE_2, MRZ_TD1_LINE_1, MRZ_TD1_LINE_2, MRZ_TD1_LINE_3. 2. National identification number — e.g. NETHERLANDS_BSN_NUMBER, FRANCE_NIR, SPAIN_DNI_NUMBER, POLAND_PESEL_NUMBER, GERMANY_IDENTITY_CARD_NUMBER. 3. Portrait photo — OBJECT_TYPE/PERSON/FACE (optional per request). 4. Signature — OBJECT_TYPE/PERSON/SIGNATURE. Legal driver: under Dutch UAVG art. 46 (and equivalent national-ID restrictions across the EU) organisations may verify identity but may not retain the national identification number. IDBird supports data minimisation: the archived copy holds as little unnecessary personal data as possible. ## Authentication HTTP bearer token: `Authorization: Bearer idb_…` (prefix `idb_` + 40 chars). Keys are issued by the IDBird team (contact info@idbird.eu), stored server-side as SHA-256 hashes only, checked live on every request; revocation is effective on the next request. Missing/unknown/revoked key → 401 invalid_api_key. ## Endpoints - POST https://api.idbird.eu/v1/redact — redact a document, return image(s) + findings + warnings - POST https://api.idbird.eu/v1/inspect — findings + warnings only; no image is ever returned - GET https://api.idbird.eu/up — health check, no auth ## Request (identical for both POST endpoints) Content-Type: multipart/form-data | field | required | value | |---|---|---| | document | yes | JPEG, PNG, BMP or PDF (up to 5 pages by default), max 10 MiB. Type is sniffed from content; filename and Content-Type are ignored. | | country_hint | no | ISO 3166-1 alpha-2 of the issuing country, case-insensitive. EL is an alias for GR. Omit for auto mode. | | photo_redaction | no | redact (default) / keep / both | Example: curl https://api.idbird.eu/v1/redact \ -H "Authorization: Bearer idb_XXXX" \ -F document=@scan.jpg \ -F country_hint=NL ## Responses (HTTP 200) `image` is always a base64-encoded PNG and always the most-redacted artifact. `warnings` (array) and `findings` (object of detector name → count) are always present — empty when clean. Values are never returned, only detector names and counts. POST /v1/redact, single page: { "image": "iVBORw0KGgoAAAANSUhEUgAA…", "warnings": [], "findings": { "MRZ_TD3_LINE_1": 1, "MRZ_TD3_LINE_2": 1, "NETHERLANDS_PASSPORT": 1, "OBJECT_TYPE/PERSON/FACE": 2, "OBJECT_TYPE/PERSON/SIGNATURE": 1 } } POST /v1/redact with photo_redaction=both adds a sibling key `image_photo_visible` (portrait intact, everything else redacted). With photo_redaction=keep, the single image keeps the portrait and `warnings` contains "photo_not_redacted". POST /v1/redact, multi-page PDF: `image` is absent; a `pages` array appears with 1-based page numbers, plus aggregate warnings/findings at top level: { "pages": [ { "page": 1, "image": "iVBORw0KGgo…", "findings": { "OBJECT_TYPE/PERSON/FACE": 1 } }, { "page": 2, "image": "iVBORw0KGgo…", "findings": { "MRZ_TD3_LINE_2": 1, "NETHERLANDS_BSN_NUMBER": 1 } } ], "warnings": [], "findings": { "MRZ_TD3_LINE_2": 1, "NETHERLANDS_BSN_NUMBER": 1, "OBJECT_TYPE/PERSON/FACE": 1 } } A single-page PDF returns the flat `image` envelope. POST /v1/inspect (never returns an image): { "findings": { "NETHERLANDS_BSN_NUMBER": 1, "MRZ_TD3_LINE_2": 1 }, "warnings": ["no_country_hint"] } ## The graded coverage contract (IMPORTANT) HTTP 200 means processed, NOT fully protected. Callers MUST branch on `warnings` before archiving output. Warning codes, emitted in this fixed order: - nothing_detected — nothing sensitive found; image returned unchanged - no_country_hint — national-number detection ran in auto mode - country_detectors_unavailable — issuing country supported for MRZ only - country_detector_no_match — country detectors ran, no national number matched - mrz_not_found — no machine-readable zone found - missing_face_finding — no portrait photo detected - missing_signature_finding — no signature detected - photo_not_redacted — caller chose to keep the photo; a recognisable face remains ## Errors One envelope, stable codes, static English messages: { "error": { "code": "…", "message": "…" } } | HTTP | code | message | |---|---|---| | 401 | invalid_api_key | The bearer API key is missing, unknown, or revoked. | | 404 | not_found | Not found. | | 405 | method_not_allowed | Method not allowed. | | 413 | payload_too_large | The document exceeds the 10 MiB limit. | | 415 | unsupported_media_type | The document must be a JPEG, PNG, BMP or PDF; the type is detected from file content. | | 422 | country_hint_invalid | The country_hint must be a two-letter ISO 3166-1 alpha-2 code. | | 422 | country_not_supported | The issuing country "US" is not supported by this service. | | 422 | file_required | The document file is required. | | 422 | photo_redaction_invalid | The photo_redaction field must be one of: redact, keep, both. | | 422 | too_many_pages | The PDF exceeds the 5-page limit; split it and submit the pages separately. | | 422 | pdf_encrypted | Encrypted PDFs are not supported. | | 422 | unreadable_image | The document could not be decoded as an image. | | 422 | image_normalization_failed | The image could not be reduced to the redaction backend request budget without degrading below the quality floor. | | 429 | rate_limited | Too many requests; retry later. (Retry-After header) | | 429 | daily_quota_exceeded | The daily allowance of N API call(s) for this key is exhausted for today (UTC). (Retry-After = next UTC midnight) | | 500 | internal_error | Internal error. | | 502 | dlp_unavailable | The redaction backend is unavailable; no image was produced. | ## Country coverage Full (national-number detectors + MRZ + face + signature), 15 countries: NL, DE, FR, ES, AT, BE, HR, CZ, DK, FI, IE, IT, PL, PT, SE. MRZ + face + signature only (response carries country_detectors_unavailable), 12 countries: BG, CY, EE, GR, HU, LV, LT, LU, MT, RO, SK, SI. Any other issuing country → 422 country_not_supported. ## Privacy invariants 1. No uploaded image byte is persisted anywhere — no DB, cache, queue, log or leftover file. 2. Every temp file is deleted before the response, even on exceptions. 3. No detected value ever reaches logs or audit records — detector types and counts only. 4. Every coverage gap is named in warnings. 5. Redaction is pixel-destructive; no removable overlay exists. 6. Backend failure → 5xx error, never an image. 7. EU-only processing; the service refuses to start outside the EU. EU data residency at rest, in use and in transit. ## Limits & billing - Rate limit: 30 requests/minute per key (429 rate_limited + Retry-After). - Daily allowance: 50 calls/key/day by default (UTC); raised per key by the IDBird team, effective immediately. - Billable unit: one fully processed request = one call, regardless of page count. Rejections (4xx) and failures (5xx) are never billed; quota is checked before processing. - No webhooks; fully synchronous. No self-service signup; keys via info@idbird.eu. ## Links - Website: https://idbird.eu/ (English /en/, Dutch /nl/, German /de/, French /fr/, Spanish /es/, Danish /da/, Finnish /fi/, Italian /it/) - API reference page: https://idbird.eu/en/api - OpenAPI 3.1: https://api.idbird.eu/openapi.yaml (pinned to the code by a CI test) - Interactive docs: https://api.idbird.eu/docs.html - Contact: info@idbird.eu