{"openapi":"3.1.0","info":{"title":"eCMR Capture API","version":"1.0.0","summary":"Extract the 24 canonical CMR consignment-note fields from images and PDFs.","description":"Authenticate every request with `Authorization: Bearer ek_live_…`. All responses are JSON. Errors follow the shape `{ error: { type, message, doc_url } }`.","contact":{"email":"support@ecmrcapture.com","url":"https://ecmrcapture.com/docs"},"license":{"name":"Commercial","url":"https://ecmrcapture.com/terms"}},"servers":[{"url":"https://ecmrcapture.com","description":"Production"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"ek_live_"}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["type","message"],"properties":{"type":{"type":"string","enum":["missing_authentication","invalid_api_key","revoked_api_key","rate_limit_exceeded","invalid_request","not_found","payload_too_large","unsupported_media_type","extraction_failed","internal_error"]},"message":{"type":"string"},"doc_url":{"type":"string","format":"uri"}}}}},"Field":{"type":"object","required":["value","confidence","source"],"properties":{"value":{"description":"Normalized value, or null when missing/illegible."},"confidence":{"type":"number","minimum":0,"maximum":1},"source":{"type":"string","enum":["extracted","missing","illegible"]}}},"CmrExtraction":{"type":"object","description":"All 24 CMR boxes per UNECE 1956 Convention, plus a warnings list.","properties":{"box_01_sender":{"$ref":"#/components/schemas/Field"},"box_02_consignee":{"$ref":"#/components/schemas/Field"},"box_03_place_of_delivery":{"$ref":"#/components/schemas/Field"},"box_04_place_of_taking_over":{"$ref":"#/components/schemas/Field"},"box_05_documents_attached":{"$ref":"#/components/schemas/Field"},"box_06_marks_and_numbers":{"$ref":"#/components/schemas/Field"},"box_07_number_of_packages":{"$ref":"#/components/schemas/Field"},"box_08_method_of_packing":{"$ref":"#/components/schemas/Field"},"box_09_nature_of_goods":{"$ref":"#/components/schemas/Field"},"box_10_statistical_number":{"$ref":"#/components/schemas/Field"},"box_11_gross_weight_kg":{"$ref":"#/components/schemas/Field"},"box_12_volume_m3":{"$ref":"#/components/schemas/Field"},"box_13_senders_instructions":{"$ref":"#/components/schemas/Field"},"box_14_return_freight":{"$ref":"#/components/schemas/Field"},"box_15_cash_on_delivery":{"$ref":"#/components/schemas/Field"},"box_16_carrier":{"$ref":"#/components/schemas/Field"},"box_17_successive_carrier":{"$ref":"#/components/schemas/Field"},"box_18_carriers_reservations":{"$ref":"#/components/schemas/Field"},"box_19_special_agreements":{"$ref":"#/components/schemas/Field"},"box_20_to_be_paid_by":{"$ref":"#/components/schemas/Field"},"box_21_drawn_up_at":{"$ref":"#/components/schemas/Field"},"box_22_signature_of_sender":{"$ref":"#/components/schemas/Field"},"box_23_signature_of_carrier":{"$ref":"#/components/schemas/Field"},"box_24_signature_of_consignee":{"$ref":"#/components/schemas/Field"},"warnings":{"type":"array","items":{"type":"string"}}}},"Extraction":{"type":"object","required":["object","id","status","created_at"],"properties":{"object":{"type":"string","const":"extraction"},"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","processing","completed","low_confidence","error"]},"confidence":{"type":"number","nullable":true,"minimum":0,"maximum":1},"fields":{"$ref":"#/components/schemas/CmrExtraction"},"file":{"type":"object","properties":{"mime":{"type":"string","nullable":true},"size_bytes":{"type":"integer","nullable":true}}},"poll_url":{"type":"string","description":"Present only on async submission responses."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time","nullable":true}}},"ExtractionList":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Extraction"}},"has_more":{"type":"boolean"},"next_cursor":{"type":"string","nullable":true}}},"WebhookEndpoint":{"type":"object","properties":{"object":{"type":"string","const":"webhook_endpoint"},"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"description":{"type":"string","nullable":true},"events":{"type":"array","items":{"type":"string","enum":["extraction.completed","extraction.low_confidence"]}},"status":{"type":"string","enum":["active","disabled"]},"consecutive_failures":{"type":"integer"},"last_success_at":{"type":"string","format":"date-time","nullable":true},"last_failure_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"signing_secret":{"type":"string","description":"Returned exactly once, on create. Store it; we cannot show it again."}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Per-key rate limit exceeded.","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the next allowed request."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No such resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"security":[{"bearerAuth":[]}],"paths":{"/v1/extractions":{"post":{"operationId":"createExtractionSync","summary":"Create a synchronous extraction (≤10 MB).","description":"Returns the parsed extraction inline. Use this for interactive flows where latency matters (≈8–15 s).","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Extraction succeeded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Extraction"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"description":"File exceeds 10 MB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"415":{"description":"Unsupported file type. Use jpg, jpeg, png, webp, or gif.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"description":"Upstream extraction model failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listExtractions","summary":"List recent extractions for the org.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","processing","completed","low_confidence","error"]}},{"name":"starting_after","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractionList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/extractions/async":{"post":{"operationId":"createExtractionAsync","summary":"Submit an extraction for background processing (≤25 MB).","description":"Returns 202 immediately. Subscribe to `extraction.completed` and `extraction.low_confidence` webhooks to be notified.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"202":{"description":"Accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Extraction"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"413":{"description":"File exceeds 25 MB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/extractions/{id}":{"get":{"operationId":"getExtraction","summary":"Fetch one extraction by id.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Extraction"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/webhooks":{"post":{"operationId":"createWebhook","summary":"Register a webhook endpoint.","description":"Returns the signing secret exactly once.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"HTTPS URL."},"description":{"type":"string","maxLength":200},"events":{"type":"array","items":{"type":"string","enum":["extraction.completed","extraction.low_confidence"]}}}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"description":"Validation error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"get":{"operationId":"listWebhooks","summary":"List all webhook endpoints for the org.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/webhooks/{id}":{"get":{"operationId":"getWebhook","summary":"Fetch one webhook endpoint.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"disableWebhook","summary":"Disable a webhook endpoint (soft delete).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}