{"openapi":"3.0.3","info":{"title":"eCMR API","version":"1.0.0","description":"REST API for creating, issuing, signing and sharing electronic consignment\nnotes, built by 40 PÉS.\n\nCompliant with the CMR Convention, eIDAS (EU 910/2014) and GDPR (EU 2016/679).\n\n## Response envelope\n\nEvery JSON response uses the same envelope. On success:\n\n    { \"success\": true, \"data\": { ... }, \"meta\": { \"timestamp\": \"...\" } }\n\nOn failure:\n\n    { \"success\": false,\n      \"error\": { \"code\": \"...\", \"message\": \"...\", \"details\": [] },\n      \"meta\": { \"timestamp\": \"...\" } }\n\nEndpoints that return a PDF are the only exception; they answer with\n`application/pdf`.\n\n## Authentication\n\nTenant endpoints take an `X-API-Key` header. Reseller endpoints take an\n`X-Master-API-Key` header. Only signup, verification, health and version\nneed no credentials.\n\n## Rate limiting\n\nEach API key has a budget of requests per minute (`rate_limit_per_minute`\non the account, 600 for a tenant by default), counted in fixed one-minute\nwindows that start on the minute. Reads (`GET`) see a budget about ten\npercent smaller than writes, so polling can never crowd out creating,\nissuing or signing a document.\n\nEvery authenticated response carries `X-RateLimit-Limit` (the budget for\nthat kind of request), `X-RateLimit-Remaining` and `X-RateLimit-Reset`\n(Unix time at which the window ends). A request past the budget is\nanswered `429` with code `RATE_LIMIT_EXCEEDED` and a `Retry-After` header\nin seconds; back off until then rather than retrying at once. Rejected\nrequests do not consume the budget.\n\n## Conditional requests\n\n`GET` responses for documents, DeCA and statistics carry an `ETag`.\nSend it back in `If-None-Match` and an unchanged resource answers `304`\nwith no body. The list endpoints' `total_count` counts the documents that\nmatch the filters given, not every document on the account.\n\n## Webhook delivery\n\nWhen a tenant has a webhook URL configured, each lifecycle event it\nsubscribes to is POSTed there as JSON, with `X-eCMR-Event` carrying the\nevent name, `X-eCMR-Delivery` a unique id for the event and\n`X-Webhook-Signature` an HMAC-SHA256 hex digest of the raw body, keyed by\nthe webhook secret. The events are `issued`, `accepted`, `delivered`,\n`completed` and `cancelled`; a webhook with no event list stored receives\nall of them. The body is:\n\n    { \"event_id\": \"...\",\n      \"event\": \"issued\",\n      \"occurred_at\": \"...\",\n      \"tenant_id\": \"...\",\n      \"document\": { \"id\": 1, \"cmr_number\": \"...\", \"status\": \"...\",\n                    \"external_reference\": \"...\", \"document_type\": \"cmr\",\n                    \"carrier\": \"...\", \"consignor\": \"...\", \"consignee\": \"...\",\n                    \"created_at\": \"...\", \"updated_at\": \"...\" },\n      \"data\": { },\n      \"timestamp\": \"...\" }\n\n`document` is the same summary the list endpoint returns, so most\nreceivers need no call back. A tenant managed by a reseller also carries\n`reseller_id`, `reseller_reference` and `vat_number`, and is delivered to\nthe reseller's webhook, filtered by the reseller's event list, whenever the\nreseller has one configured.\n\nAny answer other than 2xx, a timeout or a connection error is retried\nwith a growing wait, up to 8 attempts over about 80 minutes; after that\nthe delivery is marked failed. Retries resend the same body with the same\n`event_id`, so a receiver that sees an `event_id` twice has already handled\nit. Events can arrive out of order; `occurred_at` says which is newer. A\nreceiver that was down longer than the retries can catch up with\n`GET /documents?updated_after=...`.\n\nThe test endpoints are not filtered: they always POST a `webhook.test`\nevent to the configured address.\n\n## Languages\n\nDocuments and emails are produced in Portuguese, English, Spanish, German,\nFrench or Italian, resolved from the tenant's `default_locale`.\n","contact":{"name":"40 PÉS","email":"info@40pes.pt","url":"https://40pes.pt"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://ecmr.40pes.pt/api/v1/ecmr","description":"Production"},{"url":"https://ecmr.dev.40pes.pt/api/v1/ecmr","description":"Development"}],"tags":[{"name":"Status","description":"Health and version, no authentication."},{"name":"Signup","description":"Public tenant registration and email verification."},{"name":"Reseller signup","description":"Public reseller registration and email verification."},{"name":"Tenant","description":"The authenticated tenant's own profile, usage and webhook."},{"name":"Documents","description":"Create, read, update and search eCMR documents."},{"name":"Lifecycle","description":"Move a document between draft, issued, delivered and cancelled."},{"name":"Signatures","description":"Request, validate and collect signatures from the three parties."},{"name":"Shares","description":"Tokenised links and QR codes giving access to a document."},{"name":"DeCA","description":"Spain's documento electronico de control administrativo, mandatory for domestic transport from 5 October 2026. No states, no signatures."},{"name":"Reseller","description":"Partner endpoints for managing sub-tenants and billing."}],"security":[{"ApiKeyAuth":[]}],"paths":{"/health":{"get":{"tags":["Status"],"summary":"Service health","operationId":"getHealth","description":"Reports the status of the API, the database and the PDF service.","security":[],"responses":{"200":{"description":"Health report.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"healthy"},"service":{"type":"string"},"version":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"checks":{"type":"object"}}}}}},"503":{"description":"One or more checks failed."}}}},"/version":{"get":{"tags":["Status"],"summary":"API version","operationId":"getVersion","security":[],"responses":{"200":{"description":"Version and supported API versions.","content":{"application/json":{"schema":{"type":"object","properties":{"api_version":{"type":"string"},"supported_versions":{"type":"array","items":{"type":"string"}},"deprecations":{"type":"array","items":{"type":"string"}},"changelog_url":{"type":"string","format":"uri"}}}}}}}}},"/openapi":{"get":{"tags":["Status"],"summary":"This specification","operationId":"getOpenapi","description":"Serves this document, so a client can fetch the contract from the\nenvironment it is actually talking to. Request `openapi.yaml` or\n`openapi.json`.\n","security":[],"responses":{"200":{"description":"The OpenAPI specification.","content":{"application/yaml":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"object"}}}}}}},"/signup":{"post":{"tags":["Signup"],"summary":"Register a company","operationId":"postSignup","description":"Creates a tenant in `pending_verification` and emails a verification\nlink. The API key is issued only once the email is verified.\n","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}}},"responses":{"201":{"description":"Tenant created, verification email sent.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SignupResult"}}}]}}}},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/signup/verify":{"get":{"tags":["Signup"],"summary":"Verify a company's email","operationId":"getSignupVerify","description":"Activates the tenant and returns its API key. This is the only moment\nthe key is shown in full. Requested with `Accept: text/html` it renders\na confirmation page instead.\n","security":[],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"Token from the verification email. Valid for 24 hours."}],"responses":{"200":{"description":"Email verified, tenant active.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VerifiedTenant"}}}]}},"text/html":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"410":{"description":"The token has expired. Request a new one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/signup/resend_verification":{"post":{"tags":["Signup"],"summary":"Resend the verification email","operationId":"postSignupResendVerification","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"Verification email sent again.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ResendVerificationResult"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/tenant/profile":{"get":{"tags":["Tenant"],"summary":"Read the tenant profile","operationId":"getTenantProfile","responses":{"200":{"description":"The authenticated tenant.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TenantProfile"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"put":{"tags":["Tenant"],"summary":"Update the tenant profile","operationId":"putTenantProfile","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantUpdate"}}}},"responses":{"200":{"description":"Profile updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TenantProfile"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/tenant/usage":{"get":{"tags":["Tenant"],"summary":"Usage statistics","operationId":"getTenantUsage","description":"Document counts and API consumption for the current tenant.","responses":{"200":{"description":"Usage figures.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/TenantUsage"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/tenant/webhook":{"get":{"tags":["Tenant"],"summary":"Read the webhook configuration","operationId":"getTenantWebhook","responses":{"200":{"description":"Current webhook settings.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookConfig"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"put":{"tags":["Tenant"],"summary":"Update the webhook configuration","operationId":"putTenantWebhook","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookUpdate"}}}},"responses":{"200":{"description":"Webhook updated. A secret is generated when a URL is set.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookUpdateResult"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/tenant/test_webhook":{"post":{"tags":["Tenant"],"summary":"Send a test event to the webhook","operationId":"postTenantTestWebhook","responses":{"200":{"description":"Test delivery attempted; the result describes the outcome.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookTestResult"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents":{"get":{"tags":["Documents"],"summary":"List documents","operationId":"getDocuments","parameters":[{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/DocumentStatus"}},{"name":"search","in":"query","description":"Free text, matched against the number, the external reference and the names of the parties. Case-insensitive and partial - \"acme\" finds \"Acme Iberica SL\".","schema":{"type":"string"}},{"name":"external_reference","in":"query","schema":{"type":"string"}},{"name":"created_after","in":"query","schema":{"type":"string","format":"date"}},{"name":"created_before","in":"query","schema":{"type":"string","format":"date"}},{"name":"updated_after","in":"query","description":"Only documents changed after this instant, for catching up on missed webhooks. Pair it with `sort_by=updated_at\u0026sort_order=asc`.","schema":{"type":"string","format":"date-time"}},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"},{"name":"sort_by","in":"query","schema":{"type":"string","enum":["created_at","updated_at","cmr_number","status","issued_at","completed_at"]}},{"name":"sort_order","in":"query","schema":{"type":"string","enum":["asc","desc"]}}],"responses":{"200":{"description":"A page of documents.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DocumentSummary"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Documents"],"summary":"Create a document","operationId":"postDocuments","description":"The document is created as `draft`. Issue it to make it effective.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document"],"properties":{"document":{"$ref":"#/components/schemas/DocumentInput"}}}}}},"responses":{"201":{"description":"Document created.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Document"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/search":{"get":{"tags":["Documents"],"summary":"Search documents","operationId":"getDocumentsSearch","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"Free text matched against CMR number, references and party names."},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"Matching documents.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DocumentSummary"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/documents/statistics":{"get":{"tags":["Documents"],"summary":"Document statistics","operationId":"getDocumentsStatistics","description":"Counts by status and recent activity for the current tenant. The top-level counts are eCMR only; DeCA counts come under `deca`.","responses":{"200":{"description":"Statistics.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DocumentStatistics"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/documents/validate":{"post":{"tags":["Documents"],"summary":"Validate a payload without creating anything","operationId":"postDocumentsValidate","description":"Runs the same validation as create and reports what would fail.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document"],"properties":{"document":{"$ref":"#/components/schemas/DocumentInput"}}}}}},"responses":{"200":{"description":"Validation result.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"valid":{"type":"boolean"},"errors":{"type":"array","items":{"type":"string"}},"warnings":{"type":"array","description":"Never make the document invalid.","items":{"type":"string"}}}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"get":{"tags":["Documents"],"summary":"Read a document","operationId":"getDocumentsByCmrNumber","responses":{"200":{"description":"The document.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Document"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"tags":["Documents"],"summary":"Replace a document","operationId":"putDocumentsByCmrNumber","description":"Which fields may change depends on the status. A signed document\naccepts only the observation fields of parties that have not signed.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document"],"properties":{"document":{"$ref":"#/components/schemas/DocumentInput"}}}}}},"responses":{"200":{"description":"Document updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Document"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}},"patch":{"tags":["Documents"],"summary":"Update a document","operationId":"patchDocumentsByCmrNumber","description":"Same rules as PUT; send only the fields you are changing.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["document"],"properties":{"document":{"$ref":"#/components/schemas/DocumentInput"}}}}}},"responses":{"200":{"description":"Document updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Document"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}},"delete":{"tags":["Documents"],"summary":"Delete a document","operationId":"deleteDocumentsByCmrNumber","description":"Only a draft can be deleted. Issued documents are cancelled instead.","responses":{"200":{"description":"Document deleted.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"message":{"type":"string"}}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/pdf":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"get":{"tags":["Documents"],"summary":"Download the PDF","operationId":"getDocumentsByCmrNumberPdf","parameters":[{"name":"locale","in":"query","schema":{"$ref":"#/components/schemas/Locale"},"description":"Overrides the tenant's default language."},{"name":"bilingual","in":"query","schema":{"type":"boolean"},"description":"Renders the document in the chosen language alongside English."}],"responses":{"200":{"description":"The consignment note as a PDF.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/documents/{cmr_number}/pdf/{role}":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"},{"name":"role","in":"path","required":true,"schema":{"$ref":"#/components/schemas/SignatoryRole"}}],"get":{"tags":["Documents"],"summary":"Download the PDF as it stood for one party","operationId":"getDocumentsByCmrNumberPdfByRole","description":"The snapshot taken when that party signed, which is what they legally\nagreed to rather than the current state.\n","responses":{"200":{"description":"The snapshot as a PDF.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/documents/{cmr_number}/history":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"get":{"tags":["Documents"],"summary":"Audit trail","operationId":"getDocumentsByCmrNumberHistory","description":"Every recorded change, signature and share, in order.","responses":{"200":{"description":"The audit trail.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/DocumentVersionEntry"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/documents/{cmr_number}/compliance":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"get":{"tags":["Documents"],"summary":"Compliance report","operationId":"getDocumentsByCmrNumberCompliance","description":"Checks the document against the CMR Convention and eIDAS requirements.","responses":{"200":{"description":"The compliance report.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ComplianceReport"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/documents/{cmr_number}/lifecycle/issue":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"post":{"tags":["Lifecycle"],"summary":"Issue a document","operationId":"postDocumentsByCmrNumberLifecycleIssue","description":"Moves a draft to `issued`, after which it can be signed.","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"location":{"type":"string","description":"Where the transition happened."}}}}}},"responses":{"200":{"description":"Document issued.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LifecycleTransition"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/lifecycle/cancel":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"post":{"tags":["Lifecycle"],"summary":"Cancel a document","operationId":"postDocumentsByCmrNumberLifecycleCancel","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string"}}}}}},"responses":{"200":{"description":"Document cancelled.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LifecycleTransition"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/lifecycle/status":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"get":{"tags":["Lifecycle"],"summary":"Lifecycle status","operationId":"getDocumentsByCmrNumberLifecycleStatus","description":"Current status, which transitions are allowed, and signature progress.","responses":{"200":{"description":"The lifecycle status.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/LifecycleStatus"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/documents/{cmr_number}/signatures":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"get":{"tags":["Signatures"],"summary":"List signatures","operationId":"getDocumentsByCmrNumberSignatures","responses":{"200":{"description":"Signatures on the document.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Signature"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Signatures"],"summary":"Request a signature","operationId":"postDocumentsByCmrNumberSignatures","description":"For `remote`, the signatory receives a link by email or SMS and\nvalidates a one-time code before signing. For `in_person`, the\nsignature is captured on the device holding the document.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignatureRequest"}}}},"responses":{"201":{"description":"Signature requested.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RequestedSignature"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/signatures/{id}":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"},{"$ref":"#/components/parameters/SignatureId"}],"get":{"tags":["Signatures"],"summary":"Read a signature","operationId":"getDocumentsByCmrNumberSignaturesById","responses":{"200":{"description":"The signature.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Signature"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/documents/{cmr_number}/signatures/{id}/validate_otp":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"},{"$ref":"#/components/parameters/SignatureId"}],"post":{"tags":["Signatures"],"summary":"Validate the one-time code","operationId":"postDocumentsByCmrNumberSignaturesByIdValidateOtp","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["otp_code"],"properties":{"otp_code":{"type":"string","description":"The code sent to the signatory."},"geolocation":{"$ref":"#/components/schemas/Geolocation"}}}}}},"responses":{"200":{"description":"Code accepted; the signature may now be captured.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SignatureResult"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/signatures/{id}/sign":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"},{"$ref":"#/components/parameters/SignatureId"}],"post":{"tags":["Signatures"],"summary":"Sign","operationId":"postDocumentsByCmrNumberSignaturesByIdSign","description":"Records the signature and takes an immutable snapshot of the document\nas it stood. Send either a drawn signature or a certificate.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignPayload"}}}},"responses":{"200":{"description":"Signed.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SignatureResult"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/signatures/{id}/cancel":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"},{"$ref":"#/components/parameters/SignatureId"}],"post":{"tags":["Signatures"],"summary":"Cancel a signature request","operationId":"postDocumentsByCmrNumberSignaturesByIdCancel","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Recorded with the cancellation. Defaults to \"Cancelled by user\"."}}}}}},"responses":{"200":{"description":"Request cancelled.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SignatureCancelResult"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/signatures/{id}/resend_otp":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"},{"$ref":"#/components/parameters/SignatureId"}],"post":{"tags":["Signatures"],"summary":"Resend the one-time code","operationId":"postDocumentsByCmrNumberSignaturesByIdResendOtp","responses":{"200":{"description":"A new code was sent.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OtpResendResult"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/shares":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"get":{"tags":["Shares"],"summary":"List shares","operationId":"getDocumentsByCmrNumberShares","responses":{"200":{"description":"Every share created for the document.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Share"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"post":{"tags":["Shares"],"summary":"Create a share","operationId":"postDocumentsByCmrNumberShares","description":"Produces a tokenised link. `view` grants read-only access; `carrier`\nadditionally allows assigning a driver and requesting signatures.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["share"],"properties":{"share":{"$ref":"#/components/schemas/ShareInput"}}}}}},"responses":{"201":{"description":"Share created.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreatedShare"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/shares/active":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"get":{"tags":["Shares"],"summary":"List active shares","operationId":"getDocumentsByCmrNumberSharesActive","description":"Shares that have not expired and have not been revoked.","responses":{"200":{"description":"Active shares.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Share"}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/documents/{cmr_number}/shares/generate_qr":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"}],"post":{"tags":["Shares"],"summary":"Generate a QR code","operationId":"postDocumentsByCmrNumberSharesGenerateQr","description":"Creates a fresh view-only share and returns its QR code, for printing or\nshowing at a checkpoint. It takes no `share` object: the only input is\nhow long the link should last.\n","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QrShareInput"}}}},"responses":{"200":{"description":"The QR code, as a data URI, and the URL behind it.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"share":{"$ref":"#/components/schemas/Share"},"qr_code_url":{"type":"string","format":"uri"},"qr_code_svg":{"type":"string","description":"The QR code as SVG markup."},"qr_code_base64":{"type":"string","description":"The QR code as a base64 PNG."}}}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/documents/{cmr_number}/shares/{token}":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"},{"$ref":"#/components/parameters/ShareToken"}],"get":{"tags":["Shares"],"summary":"Read a share","operationId":"getDocumentsByCmrNumberSharesByToken","responses":{"200":{"description":"The share.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Share"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/documents/{cmr_number}/shares/{token}/revoke":{"parameters":[{"$ref":"#/components/parameters/CmrNumber"},{"$ref":"#/components/parameters/ShareToken"}],"post":{"tags":["Shares"],"summary":"Revoke a share","operationId":"postDocumentsByCmrNumberSharesByTokenRevoke","description":"The link stops working immediately.","responses":{"200":{"description":"Share revoked.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ShareRevokeResult"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/deca":{"get":{"tags":["DeCA"],"summary":"List DeCA documents","operationId":"getDeca","parameters":[{"name":"search","in":"query","description":"Free text, matched against the number, the external reference and the names of the parties. Case-insensitive and partial - \"acme\" finds \"Acme Iberica SL\".","schema":{"type":"string"}},{"name":"external_reference","in":"query","schema":{"type":"string"}},{"name":"created_after","in":"query","schema":{"type":"string","format":"date"}},{"name":"created_before","in":"query","schema":{"type":"string","format":"date"}},{"name":"updated_after","in":"query","description":"Only DeCA changed after this instant.","schema":{"type":"string","format":"date-time"}},{"name":"sort_order","in":"query","description":"By creation time; newest first unless `asc`.","schema":{"type":"string","enum":["asc","desc"]}},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"A page of DeCA documents.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Deca"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["DeCA"],"summary":"Create a DeCA document","operationId":"postDeca","description":"Creates a documento electronico de control administrativo and generates\nits PDF at once, before the service starts, as the Resolucion of\n5 June 2026 requires. The response carries `deca.download_url`: that is\nthe address encoded in the QR code printed on the PDF, and it is also\nthe address the enforcement officer opens at the roadside.\n\nThat URL is public by design. It answers with the stored PDF directly,\nwith no page, no login and no redirect, and it stops working one year\nafter the later of the loading and delivery dates. Print the QR, or\nhand the driver `deca.qr_code_base64`.\n\nTo send the document to a driver use `deca.view_url` instead: the same\ntoken opened as a page, with the document on screen, the QR next to it\nand the PDF openable in the browser. `download_url` handed to a phone\nmakes it ask where to save a file, which is the wrong thing to have in\nyour hand at a roadside check.\n\nA DeCA has no lifecycle and takes no signatures: signature of\nadministrative control documents is not mandatory. A vehicle\nregistration is mandatory, and a trailer registration too when\n`transport.articulated` is true.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["deca"],"properties":{"deca":{"$ref":"#/components/schemas/DecaInput"}}}}}},"responses":{"201":{"description":"DeCA created and its PDF generated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deca"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/deca/{deca_number}":{"parameters":[{"$ref":"#/components/parameters/DecaNumber"}],"get":{"tags":["DeCA"],"summary":"Read a DeCA document","operationId":"getDecaByDecaNumber","responses":{"200":{"description":"The DeCA document.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deca"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/deca/{deca_number}/pdf":{"parameters":[{"$ref":"#/components/parameters/DecaNumber"}],"get":{"tags":["DeCA"],"summary":"Download the DeCA PDF","operationId":"getDecaByDecaNumberPdf","description":"Returns the stored file, the same bytes the public QR URL serves. Use\nthis one when you want the PDF under your API key; use\n`deca.download_url` for the roadside.\n","parameters":[{"name":"view","in":"query","schema":{"type":"boolean"},"description":"Serves the file inline instead of as an attachment."}],"responses":{"200":{"description":"The DeCA as a PDF.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/deca/{deca_number}/access":{"parameters":[{"$ref":"#/components/parameters/DecaNumber"}],"patch":{"tags":["DeCA"],"summary":"Extend the public access to a DeCA","operationId":"patchDecaByDecaNumberAccess","description":"Moves the expiry of the public addresses forward, keeping the token, so\nthe QR already printed on the PDF and already in a driver's hands goes\non working. Send it with no body for another year from now, or with\n`expires_at` for a date of your own. An earlier date is ignored: the\nexpiry only ever moves forward.\n","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"expires_at":{"type":"string","format":"date-time","description":"The new expiry. Defaults to a year from now."}}}}}},"responses":{"200":{"description":"The DeCA, with its new expiry.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Deca"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/signatures/by_share/{token}":{"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"},"description":"A share token belonging to one of your own documents."}],"get":{"tags":["Signatures"],"summary":"Read a signature through its share token","operationId":"getSignaturesByShareToken","description":"Looks a share of your own up by its token and returns the document it\npoints at, the signature for the role in `signatory_role`, and the\nshare. Use it to see what you handed to a signatory, and to follow the\nshare's access count.\n\nThe signatory's own page needs no API key and is not this endpoint: it\nis the web flow at `/ecmr/sign/:token`.\n","parameters":[{"name":"signatory_role","in":"query","schema":{"$ref":"#/components/schemas/SignatoryRole"},"description":"Which signature of the document to return."}],"responses":{"200":{"description":"The signature request.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ShareSignatureView"}}}]}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reseller/signup":{"post":{"tags":["Reseller signup"],"summary":"Register as a reseller","operationId":"postResellerSignup","description":"Creates a reseller in `pending_verification` and emails a verification\nlink. The master API key is issued once the email is verified.\n","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResellerSignupRequest"}}}},"responses":{"201":{"description":"Reseller created, verification email sent.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ResellerSignupResult"}}}]}}}},"422":{"$ref":"#/components/responses/ValidationFailed"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/reseller/signup/verify":{"get":{"tags":["Reseller signup"],"summary":"Verify a reseller's email","operationId":"getResellerSignupVerify","description":"Activates the reseller and returns the master API key. This is the only\nmoment the key is shown in full; afterwards it is masked.\n","security":[],"parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string"},"description":"Token from the verification email. Valid for 24 hours."}],"responses":{"200":{"description":"Email verified, reseller active.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/VerifiedReseller"}}}]}},"text/html":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"410":{"description":"The token has expired. Request a new one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/reseller/signup/resend_verification":{"post":{"tags":["Reseller signup"],"summary":"Resend the reseller verification email","operationId":"postResellerSignupResendVerification","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"Verification email sent again.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ResendVerificationResult"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reseller/profile":{"get":{"tags":["Reseller"],"summary":"Read the reseller profile","operationId":"getResellerProfile","security":[{"MasterApiKeyAuth":[]}],"responses":{"200":{"description":"The reseller. The master API key comes back masked.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Reseller"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"put":{"tags":["Reseller"],"summary":"Replace the reseller profile","operationId":"putResellerProfile","security":[{"MasterApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResellerUpdate"}}}},"responses":{"200":{"description":"Profile updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Reseller"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}},"patch":{"tags":["Reseller"],"summary":"Update the reseller profile","operationId":"patchResellerProfile","security":[{"MasterApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResellerUpdate"}}}},"responses":{"200":{"description":"Profile updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Reseller"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/reseller/tenants":{"get":{"tags":["Reseller"],"summary":"List sub-tenants","operationId":"getResellerTenants","security":[{"MasterApiKeyAuth":[]}],"parameters":[{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/AccountStatus"}},{"name":"search","in":"query","description":"Matches part of the tenant name.","schema":{"type":"string"}},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"A page of sub-tenants.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ManagedTenantSummary"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"tags":["Reseller"],"summary":"Create a sub-tenant","operationId":"postResellerTenants","description":"The tenant is created active, with no email verification, and its API\nkey is returned once. The reseller vouches for the company.\n","security":[{"MasterApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResellerTenantInput"}}}},"responses":{"201":{"description":"Sub-tenant created.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CreatedManagedTenant"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/reseller/tenants/{tenant_id}":{"parameters":[{"$ref":"#/components/parameters/TenantId"}],"get":{"tags":["Reseller"],"summary":"Read a sub-tenant","operationId":"getResellerTenantsByTenantId","security":[{"MasterApiKeyAuth":[]}],"responses":{"200":{"description":"The sub-tenant.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ManagedTenant"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/reseller/tenants/{tenant_id}/suspend":{"parameters":[{"$ref":"#/components/parameters/TenantId"}],"post":{"tags":["Reseller"],"summary":"Suspend a sub-tenant","operationId":"postResellerTenantsByTenantIdSuspend","description":"Its API key stops working; its documents are kept.","security":[{"MasterApiKeyAuth":[]}],"responses":{"200":{"description":"Sub-tenant suspended.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ManagedTenantStatusChange"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/reseller/tenants/{tenant_id}/activate":{"parameters":[{"$ref":"#/components/parameters/TenantId"}],"post":{"tags":["Reseller"],"summary":"Activate a sub-tenant","operationId":"postResellerTenantsByTenantIdActivate","security":[{"MasterApiKeyAuth":[]}],"responses":{"200":{"description":"Sub-tenant activated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ManagedTenantStatusChange"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/reseller/tenants/{tenant_id}/regenerate_api_key":{"parameters":[{"$ref":"#/components/parameters/TenantId"}],"post":{"tags":["Reseller"],"summary":"Regenerate a sub-tenant's API key","operationId":"postResellerTenantsByTenantIdRegenerateApiKey","description":"The previous key stops working immediately. The new one is returned once.","security":[{"MasterApiKeyAuth":[]}],"responses":{"200":{"description":"A new API key was issued.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/RegeneratedApiKey"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/reseller/webhook":{"get":{"tags":["Reseller"],"summary":"Read the reseller webhook configuration","operationId":"getResellerWebhook","security":[{"MasterApiKeyAuth":[]}],"responses":{"200":{"description":"Current webhook settings.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookConfig"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"put":{"tags":["Reseller"],"summary":"Replace the reseller webhook configuration","operationId":"putResellerWebhook","security":[{"MasterApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookUpdate"}}}},"responses":{"200":{"description":"Webhook updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookUpdateResult"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}},"patch":{"tags":["Reseller"],"summary":"Update the reseller webhook configuration","operationId":"patchResellerWebhook","security":[{"MasterApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookUpdate"}}}},"responses":{"200":{"description":"Webhook updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookUpdateResult"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/reseller/webhook/test":{"post":{"tags":["Reseller"],"summary":"Send a test event to the reseller webhook","operationId":"postResellerWebhookTest","security":[{"MasterApiKeyAuth":[]}],"responses":{"200":{"description":"Test delivery attempted; the result describes the outcome.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/WebhookTestResult"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/ValidationFailed"}}}},"/reseller/billing":{"get":{"tags":["Reseller"],"summary":"Billing settings","operationId":"getResellerBilling","security":[{"MasterApiKeyAuth":[]}],"responses":{"200":{"description":"Billing configuration for the reseller.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ResellerBilling"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/reseller/billing/usage":{"get":{"tags":["Reseller"],"summary":"Aggregated usage across sub-tenants","operationId":"getResellerBillingUsage","security":[{"MasterApiKeyAuth":[]}],"parameters":[{"name":"start_date","in":"query","schema":{"type":"string","format":"date"}},{"name":"end_date","in":"query","schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Usage per sub-tenant and in total.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessEnvelope"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ResellerBillingUsage"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"A tenant's API key, issued on email verification."},"MasterApiKeyAuth":{"type":"apiKey","in":"header","name":"X-Master-API-Key","description":"A reseller's master API key, issued on email verification."}},"parameters":{"CmrNumber":{"name":"cmr_number","in":"path","required":true,"schema":{"type":"string"},"description":"The document's CMR number.","example":"CMR-2026-000123"},"DecaNumber":{"name":"deca_number","in":"path","required":true,"schema":{"type":"string"},"description":"The DeCA document's number.","example":"DECA-20261005091200-A1B2C3D4"},"SignatureId":{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The signature's identifier."},"ShareToken":{"name":"token","in":"path","required":true,"schema":{"type":"string"},"description":"The share token."},"TenantId":{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string"},"description":"The sub-tenant's identifier.","example":"tnt_8f2c4b1a9d3e5f70"},"Page":{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},"PerPage":{"name":"per_page","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}},"responses":{"BadRequest":{"description":"The request was malformed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Unauthorized":{"description":"The API key is missing, unknown or belongs to a suspended account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"NotFound":{"description":"No such resource for this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"ValidationFailed":{"description":"The payload was rejected; `details` lists what failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"RateLimited":{"description":"The budget for this minute is spent; code `RATE_LIMIT_EXCEEDED`.\n`Retry-After` says how many seconds to wait.\n","headers":{"Retry-After":{"description":"Seconds until the current window ends.","schema":{"type":"integer"}},"X-RateLimit-Limit":{"description":"Requests allowed per minute for this kind of request.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time at which the window ends.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}},"schemas":{"Meta":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"}}},"SuccessEnvelope":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean","description":"Always `true` on a successful response."},"data":{},"meta":{"$ref":"#/components/schemas/Meta"}}},"ErrorEnvelope":{"type":"object","required":["success","error"],"properties":{"success":{"type":"boolean","description":"Always `false` on an error response."},"error":{"type":"object","properties":{"code":{"type":"string","description":"A stable machine-readable code, such as `AUTH_INVALID_API_KEY`,\n`DOCUMENT_NOT_FOUND`, `VALIDATION_FAILED`, `LIFECYCLE_INVALID_TRANSITION`,\n`OTP_INVALID`, `SHARE_EXPIRED`, `ENDPOINT_NOT_FOUND` or `INTERNAL_ERROR`.\n"},"message":{"type":"string"},"details":{"type":"array","items":{"type":"string"}}}},"meta":{"$ref":"#/components/schemas/Meta"}}},"PaginationMeta":{"type":"object","properties":{"timestamp":{"type":"string","format":"date-time"},"page":{"type":"integer"},"per_page":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}},"Locale":{"type":"string","enum":["pt","en","es","de","fr","it"]},"AccountStatus":{"type":"string","enum":["pending_verification","active","suspended"]},"CompanyType":{"type":"string","enum":["consignor","consignee","carrier"]},"DocumentStatus":{"type":"string","enum":["draft","issued","accepted","delivered","completed","cancelled"]},"SignatoryRole":{"type":"string","enum":["consignor","carrier","consignee"]},"SignatureType":{"type":"string","enum":["remote","in_person","without_signature"]},"SignatureStatus":{"type":"string","enum":["pending","otp_sent","otp_validated","completed","cancelled"]},"SharePermission":{"type":"string","enum":["view","carrier"]},"Party":{"type":"object","description":"One of the three parties to the consignment note. When the tenant is\nitself one of the parties, the platform fills that party in from the\ntenant profile and rejects the fields you send for it.\n\nDriver and vehicle belong to `transport`, never to a party. Sending\n`driver_name`, `driver_email`, `driver_phone`, `driver_license`,\n`truck_plates`, `vehicle_registration` or `trailer_registration` inside\n`carrier`, `consignor` or `consignee` is rejected with\n`PARTY_FIELD_NOT_ALLOWED`.\n","properties":{"name":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"postal_code":{"type":"string"},"country":{"type":"string","description":"ISO 3166-1 alpha-2."},"vat_number":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"},"contact":{"type":"string","description":"Name of the person to contact."}}},"Goods":{"type":"object","description":"One line of goods. ADR fields apply to dangerous goods.","properties":{"description":{"type":"string"},"quantity":{"type":"number"},"packaging":{"type":"string"},"weight_kg":{"type":"number"},"volume_m3":{"type":"number"},"marks_and_numbers":{"type":"string"},"statistical_number":{"type":"string"},"dangerous_goods":{"type":"boolean"},"adr_class":{"type":"string"},"un_number":{"type":"string"},"adr_shipping_name":{"type":"string"},"adr_packing_group":{"type":"string"},"adr_tunnel_code":{"type":"string"},"adr_notes":{"type":"string"}}},"Transport":{"type":"object","description":"The vehicle and driver, the place of taking over the goods (CMR Box 4)\nand the place of delivery (CMR Box 3). Each place needs at least a name\nor an address, otherwise the document is rejected with\n`DOCUMENT_VALIDATION_FAILED`.\n\nThis is the only place driver and vehicle data is accepted or stored;\nthe parties carry company data only.\n","properties":{"vehicle_registration":{"type":"string","description":"Registration of the vehicle (CMR Box 16)."},"trailer_registration":{"type":"string","description":"Registration of the trailer, for an articulated vehicle."},"driver_name":{"type":"string","description":"The driver named on the consignment note. Optional at every stage: the carrier normally assigns the driver after the document is issued."},"driver_phone":{"type":"string"},"driver_email":{"type":"string","format":"email"},"driver_license":{"type":"string"},"loading_place_name":{"type":"string","description":"Name of the place of taking over the goods (CMR Box 4)."},"loading_place_address":{"type":"string","description":"Address of the place of taking over the goods, at least 5 characters."},"loading_place_country":{"type":"string","description":"ISO 3166-1 alpha-2 country code, such as `PT`."},"loading_date":{"type":"string","format":"date"},"loading_started_at":{"type":"string","format":"date-time"},"loading_completed_at":{"type":"string","format":"date-time"},"delivery_place_name":{"type":"string","description":"Name of the place of delivery (CMR Box 3)."},"delivery_place_address":{"type":"string","description":"Address of the place of delivery, at least 5 characters."},"delivery_place_country":{"type":"string","description":"ISO 3166-1 alpha-2 country code, such as `ES`."},"delivery_date":{"type":"string","format":"date"},"delivery_started_at":{"type":"string","format":"date-time"},"delivery_completed_at":{"type":"string","format":"date-time"},"successive_carriers":{"type":"array","items":{"type":"string"}}}},"Instructions":{"type":"object","properties":{"payment_terms":{"type":"string"},"cash_on_delivery":{"type":"string"},"special_agreements":{"type":"string"},"observations":{"type":"string"},"documents_attached":{"type":"array","items":{"type":"string"}}}},"DocumentInput":{"type":"object","description":"The fields accepted when creating or updating a document. A CMR number\nis assigned by the platform and cannot be set.\n","properties":{"external_reference":{"type":"string","description":"Your own reference, for reconciling with your TMS. Leave it out and the platform numbers the document itself - CMR 2026/0001, CMR 2026/0002 - counted per tenant and restarting each year. The eCMR runs its own series, apart from the DeCA, and the prefix tells them apart. Send a reference and it is kept exactly as sent, and no number is spent."},"consignor":{"$ref":"#/components/schemas/Party"},"carrier":{"$ref":"#/components/schemas/Party"},"consignee":{"$ref":"#/components/schemas/Party"},"goods":{"type":"array","items":{"$ref":"#/components/schemas/Goods"}},"transport":{"$ref":"#/components/schemas/Transport"},"instructions":{"$ref":"#/components/schemas/Instructions"},"consignor_observations":{"type":"string"},"carrier_observations":{"type":"string"},"consignee_observations":{"type":"string"},"metadata":{"type":"object","description":"Free-form JSON object with your own keys. Stored as sent and\nreturned unchanged; the platform never interprets it.\n"},"timestamps":{"$ref":"#/components/schemas/TransportTimestamps"}}},"DecaInput":{"type":"object","description":"The fields accepted when creating a DeCA. The number is assigned by the\nplatform and cannot be set. This is the eCMR payload without the\nlifecycle and the signatures, plus the two entries the Orden\nFOM/2861/2012 requires that a consignment note does not carry.\n","required":["carrier","goods","transport"],"properties":{"external_reference":{"type":"string","description":"Your own reference, for reconciling with your TMS. Leave it out and the platform numbers the DeCA itself - DECA 2026/0001, DECA 2026/0002 - counted per tenant and restarting each year. The DeCA runs its own series, apart from the eCMR, and the prefix tells them apart."},"subcontracted":{"type":"boolean","default":false,"description":"Set this when the trip was subcontracted: the carrier object is then\ntaken exactly as you send it rather than being filled from your own\nprofile, which is otherwise what happens to the slot matching your\ncompany_type. Your company becomes the cargador contractual unless\nyou send one of your own, because in a subcontract it is you who\ncontracted the transport. Without this flag, sending name, address,\ncountry, vat_number or email for your own role is still rejected.\n"},"contractual_shipper":{"allOf":[{"$ref":"#/components/schemas/Party"}],"description":"The cargador contractual of Orden FOM/2861/2012 art. 6 a): whoever\ncontracts directly with the effective carrier, which may be a\nfreight forwarder or a logistics operator rather than the consignor.\nIts name, VAT number and address are mandatory. Omit this object and\nthe consignor is used instead, in which case the consignor must\ncarry those three fields. With subcontracted set and this omitted,\nyour own company fills it.\n"},"consignor":{"$ref":"#/components/schemas/Party"},"carrier":{"allOf":[{"$ref":"#/components/schemas/Party"}],"description":"The effective carrier. Its VAT number is mandatory (art. 6 b)."},"consignee":{"allOf":[{"$ref":"#/components/schemas/Party"}],"description":"Optional. The Orden requires the place of destination, not the name\nof the consignee.\n"},"goods":{"type":"array","description":"At least one line. Every line needs a description and a positive\n`weight_kg`: art. 6 d) asks for the nature and the weight, with no\nalternative, where CMR art. 6.1 h) takes the weight or the quantity\nexpressed otherwise. A DeCA is therefore stricter than an eCMR here.\n","items":{"$ref":"#/components/schemas/Goods"}},"transport":{"$ref":"#/components/schemas/DecaTransport"},"instructions":{"$ref":"#/components/schemas/Instructions"},"consignor_observations":{"type":"string"},"carrier_observations":{"type":"string"},"consignee_observations":{"type":"string"},"metadata":{"type":"object","description":"Free-form JSON object with your own keys. Stored as sent and\nreturned unchanged; the platform never interprets it.\n"}}},"DecaTransport":{"allOf":[{"$ref":"#/components/schemas/Transport"},{"type":"object","description":"The transport of a DeCA, with the entries the Orden adds to the\neCMR ones.\n","properties":{"articulated":{"type":"boolean","description":"True for an articulated combination, which makes\n`trailer_registration` mandatory (art. 6 g).\n"},"special_authorization":{"type":"string","description":"The special circulation authorisation, for special transports\nonly (art. 6 e). Printed on the PDF when present.\n"}}}]},"DecaFile":{"type":"object","description":"The generated file and the public address its QR code encodes.","properties":{"download_url":{"type":"string","description":"Public address of the PDF. Opening it downloads the file directly,\nwith no page and no authentication. This is what the QR on the PDF\nencodes.\n"},"view_url":{"type":"string","nullable":true,"description":"The same token read as a page: the document on screen, the QR code\nnext to it and the PDF openable in the browser. This is the link to\nsend a driver, because `download_url` makes a phone ask where to\nsave a file instead of showing the document.\n"},"qr_code_base64":{"type":"string","nullable":true,"description":"The same QR code as a PNG data URL, for your own printing. Null in\nlist responses, where rendering one per row would not pay for\nitself; read a single DeCA to get it.\n"},"expires_at":{"type":"string","format":"date-time","description":"One year after the later of the loading and delivery dates. Both\naddresses stop working then. Reading the DeCA does not push this\ndate: only `PATCH /deca/{deca_number}/access` moves it, and it never\nmoves it back.\n"},"generated_at":{"type":"string","format":"date-time"},"generation_count":{"type":"integer"},"pdf_size_bytes":{"type":"integer","description":"Always at or under the 5 MB the Resolucion allows."},"pdf_sha256":{"type":"string"}}},"Deca":{"type":"object","properties":{"deca_number":{"type":"string"},"external_reference":{"type":"string","nullable":true,"description":"What you sent when the DeCA was created, or the reference the platform gave it - DECA YEAR/NUMBER, per tenant, restarting each year."},"contractual_shipper":{"$ref":"#/components/schemas/Party"},"carrier":{"$ref":"#/components/schemas/Party"},"consignor":{"$ref":"#/components/schemas/Party"},"consignee":{"$ref":"#/components/schemas/Party"},"goods":{"type":"array","items":{"$ref":"#/components/schemas/Goods"}},"transport":{"$ref":"#/components/schemas/DecaTransport"},"observations":{"type":"object","properties":{"consignor":{"type":"string","nullable":true},"carrier":{"type":"string","nullable":true},"consignee":{"type":"string","nullable":true}}},"metadata":{"type":"object","nullable":true},"created_at":{"type":"string","format":"date-time"},"scans":{"type":"array","nullable":true,"description":"Every time the QR on the PDF was read, newest first, up to the last\ntwenty. The QR hands over the file with no page in between, so this\nis the whole trace an inspection leaves: when, from which address and\non what kind of device. Present on the single-DeCA endpoints; null in\nlists.\n","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time"},"ip_address":{"type":"string","nullable":true},"device":{"type":"string","description":"iPhone, iPad, Android, Windows, Mac, Linux or unknown - read off the user agent."}}}},"deca":{"$ref":"#/components/schemas/DecaFile"}}},"DocumentSummary":{"type":"object","description":"A document as it appears in a list. The three parties are their names\nonly; the full objects come back from the single-document endpoints.\n","properties":{"id":{"type":"integer"},"cmr_number":{"type":"string"},"external_reference":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/DocumentStatus"},"carrier":{"type":"string","nullable":true},"consignor":{"type":"string","nullable":true},"consignee":{"type":"string","nullable":true},"issued_at":{"type":"string","format":"date-time","nullable":true},"completed_at":{"type":"string","format":"date-time","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"Document":{"type":"object","properties":{"id":{"type":"integer"},"cmr_number":{"type":"string"},"external_reference":{"type":"string","nullable":true,"description":"What you sent when the document was created, or the reference the platform gave it - CMR YEAR/NUMBER, per tenant, restarting each year."},"status":{"$ref":"#/components/schemas/DocumentStatus"},"consignor":{"$ref":"#/components/schemas/Party"},"carrier":{"$ref":"#/components/schemas/Party"},"consignee":{"$ref":"#/components/schemas/Party"},"goods":{"type":"array","items":{"$ref":"#/components/schemas/Goods"}},"transport":{"$ref":"#/components/schemas/Transport"},"instructions":{"$ref":"#/components/schemas/Instructions"},"consignor_observations":{"type":"string","nullable":true},"carrier_observations":{"type":"string","nullable":true},"consignee_observations":{"type":"string","nullable":true},"signatures":{"type":"array","items":{"$ref":"#/components/schemas/SignatureSummary"}},"dates":{"$ref":"#/components/schemas/DocumentDates"},"timestamps":{"$ref":"#/components/schemas/TransportTimestamps"},"locations":{"$ref":"#/components/schemas/DocumentLocations"},"integrity":{"$ref":"#/components/schemas/SignatureIntegrity"},"versions_count":{"type":"integer"},"metadata":{"type":"object","nullable":true,"description":"Free-form JSON object with your own keys, exactly as you sent it.\nNull when you stored none: an empty object breaks consumers that\nhave no dictionary type, OutSystems among them.\n"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"LifecycleStatus":{"type":"object","description":"What `GET lifecycle/status` answers: the state of the document plus what\nthe lifecycle still needs from it.\n","properties":{"cmr_number":{"type":"string"},"status":{"$ref":"#/components/schemas/DocumentStatus"},"next_required_signature":{"type":"string","nullable":true},"can_complete":{"type":"boolean"},"dates":{"$ref":"#/components/schemas/DocumentDates"},"timestamps":{"$ref":"#/components/schemas/TransportTimestamps"},"consignor_observations":{"type":"string","nullable":true},"carrier_observations":{"type":"string","nullable":true},"consignee_observations":{"type":"string","nullable":true},"signatures":{"type":"array","items":{"type":"object","properties":{"role":{"$ref":"#/components/schemas/SignatoryRole"},"status":{"$ref":"#/components/schemas/SignatureStatus"},"signatory_name":{"type":"string","nullable":true},"signed_at":{"type":"string","format":"date-time","nullable":true}}}}}},"LifecycleTransition":{"type":"object","description":"What `lifecycle/issue` and `lifecycle/cancel` answer: the new state, and\nthe four lifecycle dates at the top level rather than nested under\n`dates` as `lifecycle/status` has them.\n","properties":{"cmr_number":{"type":"string"},"status":{"$ref":"#/components/schemas/DocumentStatus"},"issued_at":{"type":"string","format":"date-time","nullable":true},"accepted_at":{"type":"string","format":"date-time","nullable":true},"delivered_at":{"type":"string","format":"date-time","nullable":true},"completed_at":{"type":"string","format":"date-time","nullable":true},"timestamps":{"$ref":"#/components/schemas/TransportTimestamps"},"consignor_observations":{"type":"string","nullable":true},"carrier_observations":{"type":"string","nullable":true},"consignee_observations":{"type":"string","nullable":true},"updated_at":{"type":"string","format":"date-time"}}},"DocumentCountsByStatus":{"type":"object","description":"Document counts grouped by status. A status with no documents is\nabsent rather than zero.\n","properties":{"draft":{"type":"integer"},"issued":{"type":"integer"},"accepted":{"type":"integer"},"delivered":{"type":"integer"},"completed":{"type":"integer"},"cancelled":{"type":"integer"}}},"TenantUsage":{"type":"object","properties":{"documents":{"type":"object","properties":{"total":{"type":"integer"},"by_status":{"$ref":"#/components/schemas/DocumentCountsByStatus"},"this_month":{"type":"integer"}}},"signatures":{"type":"object","properties":{"total":{"type":"integer"},"completed":{"type":"integer"},"pending":{"type":"integer"}}},"api_requests":{"type":"object","properties":{"rate_limit_per_minute":{"type":"integer"}}},"quota":{"type":"string","description":"The configured quota, or `unlimited` when the tenant has none."}}},"DocumentStatistics":{"type":"object","properties":{"total":{"type":"integer"},"by_status":{"$ref":"#/components/schemas/DocumentCountsByStatus"},"created_today":{"type":"integer"},"created_this_week":{"type":"integer"},"created_this_month":{"type":"integer"},"completed_this_month":{"type":"integer"},"deca":{"$ref":"#/components/schemas/DecaStatistics"}}},"DecaStatistics":{"type":"object","description":"DeCA counts, kept apart from the eCMR counts above. A DeCA is issued once and never changes status, so it has no counts by status.","properties":{"total":{"type":"integer"},"created_today":{"type":"integer"},"created_this_week":{"type":"integer"},"created_this_month":{"type":"integer"}}},"ComplianceErrorCheck":{"type":"object","properties":{"passed":{"type":"boolean"},"errors":{"type":"array","items":{"type":"string"}}}},"ComplianceWarningCheck":{"type":"object","properties":{"passed":{"type":"boolean"},"warnings":{"type":"array","items":{"type":"string"}}}},"ComplianceReport":{"type":"object","properties":{"status":{"type":"string","enum":["compliant","non_compliant"]},"checks":{"type":"object","properties":{"cmr_convention":{"$ref":"#/components/schemas/ComplianceErrorCheck"},"eidas_requirements":{"$ref":"#/components/schemas/ComplianceErrorCheck"},"data_completeness":{"$ref":"#/components/schemas/ComplianceWarningCheck"}}},"verified_at":{"type":"string","format":"date-time"}}},"ResellerBilling":{"type":"object","properties":{"reseller_id":{"type":"string"},"billing_email":{"type":"string","format":"email"},"billing_settings":{"type":"object","nullable":true,"description":"Free-form JSON object, whatever the reseller has stored. Null when\nempty.\n"},"summary":{"type":"object","properties":{"max_tenants":{"type":"integer"},"active_tenants":{"type":"integer"},"total_tenants":{"type":"integer"},"total_documents":{"type":"integer"},"total_signatures":{"type":"integer"}}},"tenants":{"type":"array","items":{"type":"object","properties":{"tenant_id":{"type":"string"},"name":{"type":"string"},"reseller_reference":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/AccountStatus"},"documents_count":{"type":"integer"},"signatures_count":{"type":"integer"}}}}}},"ResellerBillingUsage":{"type":"object","properties":{"period":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}}},"summary":{"type":"object","properties":{"documents_created":{"type":"integer"},"documents_by_status":{"$ref":"#/components/schemas/DocumentCountsByStatus"},"signatures_created":{"type":"integer"},"signatures_completed":{"type":"integer"}}},"by_tenant":{"type":"array","items":{"type":"object","properties":{"tenant_id":{"type":"string"},"name":{"type":"string"},"reseller_reference":{"type":"string","nullable":true},"documents_created":{"type":"integer"},"signatures_created":{"type":"integer"},"signatures_completed":{"type":"integer"}}}}}},"DocumentDates":{"type":"object","description":"Lifecycle dates, set by the platform as the document advances.","properties":{"issued_at":{"type":"string","format":"date-time","nullable":true},"accepted_at":{"type":"string","format":"date-time","nullable":true},"delivered_at":{"type":"string","format":"date-time","nullable":true},"completed_at":{"type":"string","format":"date-time","nullable":true}}},"DocumentLocations":{"type":"object","description":"Where each lifecycle transition was recorded.","properties":{"issued":{"type":"string","nullable":true},"accepted":{"type":"string","nullable":true},"delivered":{"type":"string","nullable":true}}},"TransportTimestamps":{"type":"object","description":"Arrival and departure times for loading and delivery. Sent on update,\nreturned on every document.\n","properties":{"loading_started_at":{"type":"string","format":"date-time","nullable":true},"loading_completed_at":{"type":"string","format":"date-time","nullable":true},"delivery_started_at":{"type":"string","format":"date-time","nullable":true},"delivery_completed_at":{"type":"string","format":"date-time","nullable":true}}},"SignatureIntegrity":{"type":"object","description":"Whether each party has signed, and what changed since.","properties":{"consignor":{"$ref":"#/components/schemas/SignatureIntegrityEntry"},"carrier":{"$ref":"#/components/schemas/SignatureIntegrityEntry"},"consignee":{"$ref":"#/components/schemas/SignatureIntegrityEntry"}}},"SignatureIntegrityEntry":{"type":"object","properties":{"signed":{"type":"boolean"},"signed_at":{"type":"string","format":"date-time","nullable":true},"signed_by":{"type":"string","nullable":true},"hash":{"type":"string","nullable":true},"changes_after_signature":{"type":"array","description":"Fields changed after this party signed. Each entry also carries\n`signed_value` and `current_value`, left undeclared here because\nthey take the JSON type of the field that changed.\n","items":{"type":"object","properties":{"field":{"type":"string"}}}}}},"DocumentVersionEntry":{"type":"object","description":"One stored version of the document, newest first. `snapshot` holds the\ndocument exactly as it stood at that version, with the raw column names\n(`carrier_data`, `transport_data`, ...), not the names used elsewhere\nin this API.\n","properties":{"version_number":{"type":"integer"},"snapshot":{"type":"object","description":"The document's stored state at this version."},"change_reason":{"type":"string","nullable":true},"created_by":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"SignatureRequest":{"type":"object","required":["signatory_role","signature_type"],"properties":{"signatory_role":{"$ref":"#/components/schemas/SignatoryRole"},"signature_type":{"$ref":"#/components/schemas/SignatureType"},"signatory_name":{"type":"string"},"contact":{"type":"string","description":"Email address or phone number in international format. Required for\n`remote`, which decides between email and SMS from the value.\n"},"preferred_locale":{"$ref":"#/components/schemas/Locale"},"geolocation":{"$ref":"#/components/schemas/Geolocation"}}},"SignPayload":{"type":"object","description":"What to send depends on the signature's `signature_type`, fixed when the\nsignature was requested:\n\n- `in_person`: `signature_image` and `biometric_data`, optionally\n  `signer_info`.\n- `certificate`: `signed_data_hash`, `digital_signature` and\n  `certificate_fingerprint`.\n- `platform`: nothing.\n- `without_signature`: `geolocation`.\n\n`geolocation` is recorded with the signature whatever the type.\n","properties":{"signature_image":{"type":"string","description":"`in_person`: the drawn signature as a PNG data URI."},"biometric_data":{"type":"object","description":"`in_person`: the stroke capture used to score the signature."},"signer_info":{"type":"object","description":"`in_person`: who signed, when it is not the named signatory.","properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"phone":{"type":"string"}}},"signed_data_hash":{"type":"string","description":"`certificate`: hash of the document that was signed."},"digital_signature":{"type":"string","description":"`certificate`: the signature over that hash."},"certificate_fingerprint":{"type":"string","description":"`certificate`: fingerprint of the signing certificate."},"geolocation":{"$ref":"#/components/schemas/Geolocation"}}},"SignatureResult":{"type":"object","description":"The outcome of a signing step. This is not the `Signature` resource: it\ncarries `signature_id`, and the extra fields depend on how the signature\nwas completed.\n","properties":{"signature_id":{"type":"integer"},"status":{"$ref":"#/components/schemas/SignatureStatus"},"signed_at":{"type":"string","format":"date-time","nullable":true},"ready_to_sign":{"type":"boolean","description":"OTP accepted, but this type still needs the sign call."},"signature_type":{"$ref":"#/components/schemas/SignatureType"},"method":{"type":"string","description":"`remote_otp` when the OTP itself completed it."},"completed":{"type":"boolean"},"already_signed":{"type":"boolean"},"confidence_score":{"type":"number","description":"`in_person`: biometric score."},"certificate_verified":{"type":"boolean"},"verification_details":{"type":"object"},"certificate_info":{"type":"object"},"acknowledgment_type":{"type":"string"},"geolocation":{"$ref":"#/components/schemas/Geolocation"}}},"SignatureCancelResult":{"type":"object","properties":{"signature_id":{"type":"integer"},"status":{"$ref":"#/components/schemas/SignatureStatus"},"cancelled":{"type":"boolean"},"reason":{"type":"string"},"document_status":{"$ref":"#/components/schemas/DocumentStatus"}}},"OtpResendResult":{"type":"object","properties":{"message":{"type":"string"},"expires_at":{"type":"string","format":"date-time"}}},"ShareSignatureView":{"type":"object","description":"The document, the signature for the requested role and the share itself.\n","properties":{"document":{"type":"object","description":"A reduced view of the document, for the signing page."},"signature":{"$ref":"#/components/schemas/Signature"},"share":{"type":"object","properties":{"token":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"access_count":{"type":"integer"}}}}},"Geolocation":{"type":"object","description":"Where the signature was taken, as reported by the signing device.","properties":{"latitude":{"type":"number"},"longitude":{"type":"number"},"accuracy":{"type":"number"}}},"SignatureSummary":{"type":"object","description":"A signature as it appears inside a document. The signature endpoints\nanswer with the fuller `Signature` instead.\n","properties":{"id":{"type":"integer"},"role":{"$ref":"#/components/schemas/SignatoryRole"},"type":{"$ref":"#/components/schemas/SignatureType"},"status":{"$ref":"#/components/schemas/SignatureStatus"},"signatory_name":{"type":"string","nullable":true},"signatory_email":{"type":"string","format":"email","nullable":true},"signatory_phone":{"type":"string","nullable":true},"signed_at":{"type":"string","format":"date-time","nullable":true},"timestamp_time":{"type":"string","format":"date-time","nullable":true},"geolocation":{"$ref":"#/components/schemas/Geolocation"}}},"Signature":{"type":"object","properties":{"id":{"type":"integer"},"document_cmr":{"type":"string"},"signature_type":{"$ref":"#/components/schemas/SignatureType"},"signatory_role":{"$ref":"#/components/schemas/SignatoryRole"},"signatory_name":{"type":"string","nullable":true},"signatory_email":{"type":"string","format":"email","nullable":true},"signatory_phone":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/SignatureStatus"},"signed_at":{"type":"string","format":"date-time","nullable":true},"has_biometric_data":{"type":"boolean"},"has_certificate":{"type":"boolean"},"metadata":{"type":"object","nullable":true,"description":"Free-form JSON object kept with the signature. Null when empty.\n"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"RequestedSignature":{"allOf":[{"$ref":"#/components/schemas/Signature"},{"type":"object","properties":{"share_token":{"type":"string","description":"Present for remote signatures; addresses the signing page."},"share_expires_at":{"type":"string","format":"date-time"}}}]},"ShareInput":{"type":"object","properties":{"share_type":{"type":"string"},"permissions":{"$ref":"#/components/schemas/SharePermission"},"recipient_email":{"type":"string","format":"email","description":"Where the link is emailed, when `send_notification` is set."},"expires_at":{"type":"string","format":"date-time"}}},"Share":{"type":"object","properties":{"token":{"type":"string"},"type":{"$ref":"#/components/schemas/SharePermission"},"url":{"type":"string","format":"uri"},"qr_code_data":{"type":"string","nullable":true,"description":"Base64 PNG of the QR code, for viewer shares only."},"recipient_email":{"type":"string","format":"email","nullable":true},"expires_at":{"type":"string","format":"date-time","nullable":true},"access_count":{"type":"integer"},"last_accessed_at":{"type":"string","format":"date-time","nullable":true},"revoked":{"type":"boolean"},"revoked_at":{"type":"string","format":"date-time","nullable":true},"active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}},"CreatedShare":{"allOf":[{"$ref":"#/components/schemas/Share"},{"type":"object","properties":{"notification_error":{"type":"string","description":"Present only when `send_notification` was asked for and sending\nfailed. The share itself was still created.\n"}}}]},"ShareRevokeResult":{"type":"object","properties":{"message":{"type":"string"},"share_token":{"type":"string"},"revoked_at":{"type":"string","format":"date-time"}}},"QrShareInput":{"type":"object","properties":{"expires_in":{"type":"integer","description":"Hours until the QR share expires. Defaults to the service default."}}},"WebhookEvent":{"type":"string","description":"A lifecycle event that can be delivered to a webhook.","enum":["issued","accepted","delivered","completed","cancelled"]},"WebhookConfig":{"type":"object","description":"The stored webhook configuration. Only the events listed are delivered;\nwith none stored, all of them are.\n","properties":{"url":{"type":"string","format":"uri","nullable":true},"configured":{"type":"boolean"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"}}}},"WebhookUpdateResult":{"type":"object","properties":{"url":{"type":"string","format":"uri","nullable":true},"secret":{"type":"string","nullable":true,"description":"Used to compute the `X-Webhook-Signature` header, an HMAC-SHA256 hex\ndigest of the raw request body. Generated when a URL is first set,\nand returned here only.\n"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"}},"message":{"type":"string"}}},"WebhookTestResult":{"type":"object","properties":{"success":{"type":"boolean"},"status_code":{"type":"integer"},"message":{"type":"string"}}},"WebhookUpdate":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"A public HTTPS address. Sending it empty clears the webhook and\ndiscards the secret.\n"},"events":{"type":"array","description":"Which events to deliver. Omit to receive all of them. An event\noutside the enum is rejected with `WEBHOOK_EVENTS_INVALID`.\n","items":{"$ref":"#/components/schemas/WebhookEvent"}}}},"SignupRequest":{"type":"object","required":["email","company_name","vat_number","address","company_type"],"properties":{"email":{"type":"string","format":"email"},"company_name":{"type":"string"},"vat_number":{"type":"string","description":"Validated against the national register where available.","example":"PT123456789"},"address":{"type":"string"},"company_type":{"$ref":"#/components/schemas/CompanyType"},"country_code":{"type":"string","description":"ISO 3166-1 alpha-2."},"rate_limit_per_minute":{"type":"integer"}}},"SignupResult":{"type":"object","properties":{"tenant_id":{"type":"string"},"email":{"type":"string","format":"email"},"company_name":{"type":"string"},"company_type":{"$ref":"#/components/schemas/CompanyType"},"address":{"type":"string"},"country_code":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/AccountStatus"},"message":{"type":"string"},"expires_in":{"type":"string"}}},"ResendVerificationResult":{"type":"object","description":"Always the same answer, whether or not the address has a pending\nverification, so the endpoint does not reveal who has an account.\n","properties":{"message":{"type":"string"},"email":{"type":"string","format":"email"},"expires_in":{"type":"string"}}},"VerifiedTenant":{"type":"object","properties":{"tenant_id":{"type":"string"},"company_name":{"type":"string"},"email":{"type":"string","format":"email"},"api_key":{"type":"string","description":"Shown only here. Store it; it cannot be read back."},"status":{"$ref":"#/components/schemas/AccountStatus"},"rate_limit_per_minute":{"type":"integer"},"message":{"type":"string"},"documentation_url":{"type":"string","format":"uri"}}},"TenantProfile":{"type":"object","description":"The authenticated tenant's own profile. `id` is the numeric record id,\nnot the public `tenant_id` returned by signup.\n","properties":{"id":{"type":"integer"},"name":{"type":"string"},"company_type":{"$ref":"#/components/schemas/CompanyType"},"address":{"type":"string"},"country_code":{"type":"string","nullable":true},"vat_number":{"type":"string"},"api_key":{"type":"string","description":"Masked, showing only the prefix and the last characters."},"contact_email":{"type":"string","format":"email","nullable":true},"contact_phone":{"type":"string","nullable":true},"active":{"type":"boolean"},"rate_limit_per_minute":{"type":"integer"},"webhook_configured":{"type":"boolean"},"settings":{"type":"object","nullable":true},"metadata":{"type":"object","nullable":true},"created_at":{"type":"string","format":"date-time"}}},"ManagedTenantSummary":{"type":"object","description":"A managed tenant as it appears in the reseller's list.","properties":{"tenant_id":{"type":"string"},"name":{"type":"string"},"vat_number":{"type":"string"},"company_type":{"$ref":"#/components/schemas/CompanyType"},"status":{"$ref":"#/components/schemas/AccountStatus"},"reseller_reference":{"type":"string","nullable":true},"documents_count":{"type":"integer"},"created_at":{"type":"string","format":"date-time"}}},"ManagedTenant":{"type":"object","properties":{"tenant_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","format":"email","nullable":true},"vat_number":{"type":"string"},"company_type":{"$ref":"#/components/schemas/CompanyType"},"address":{"type":"string"},"country_code":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/AccountStatus"},"api_key":{"type":"string","description":"Masked, showing only the prefix and the last characters."},"reseller_reference":{"type":"string","nullable":true},"rate_limit_per_minute":{"type":"integer"},"usage":{"type":"object","properties":{"documents_total":{"type":"integer"},"documents_this_month":{"type":"integer"},"signatures_total":{"type":"integer"}}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"CreatedManagedTenant":{"type":"object","properties":{"tenant_id":{"type":"string"},"api_key":{"type":"string","description":"Shown only here. Store it; it cannot be read back."},"name":{"type":"string"},"vat_number":{"type":"string"},"company_type":{"$ref":"#/components/schemas/CompanyType"},"email":{"type":"string","format":"email","nullable":true},"address":{"type":"string"},"country_code":{"type":"string","nullable":true},"status":{"$ref":"#/components/schemas/AccountStatus"},"reseller_reference":{"type":"string","nullable":true}}},"ManagedTenantStatusChange":{"type":"object","properties":{"tenant_id":{"type":"string"},"status":{"$ref":"#/components/schemas/AccountStatus"},"message":{"type":"string"}}},"RegeneratedApiKey":{"type":"object","properties":{"tenant_id":{"type":"string"},"api_key":{"type":"string","description":"The new key. Shown only here; the previous one stops working."},"message":{"type":"string"},"previous_key_prefix":{"type":"string"}}},"TenantUpdate":{"type":"object","properties":{"name":{"type":"string"},"company_type":{"$ref":"#/components/schemas/CompanyType"},"address":{"type":"string"},"country_code":{"type":"string"},"metadata":{"type":"object"}}},"ResellerSignupRequest":{"type":"object","required":["email","company_name","vat_number","address"],"properties":{"email":{"type":"string","format":"email"},"company_name":{"type":"string"},"vat_number":{"type":"string","example":"PT999888777"},"address":{"type":"string"},"country_code":{"type":"string"},"max_tenants":{"type":"integer","default":100,"description":"How many sub-tenants this reseller may create."},"rate_limit_per_minute":{"type":"integer","default":300}}},"ResellerSignupResult":{"type":"object","properties":{"reseller_id":{"type":"string"},"email":{"type":"string","format":"email"},"company_name":{"type":"string"},"address":{"type":"string"},"country_code":{"type":"string"},"status":{"$ref":"#/components/schemas/AccountStatus"},"max_tenants":{"type":"integer"},"message":{"type":"string"},"expires_in":{"type":"string"}}},"VerifiedReseller":{"type":"object","properties":{"reseller_id":{"type":"string"},"company_name":{"type":"string"},"email":{"type":"string","format":"email"},"master_api_key":{"type":"string","description":"Shown only here. Afterwards the profile returns it masked."},"max_tenants":{"type":"integer"},"status":{"$ref":"#/components/schemas/AccountStatus"},"rate_limit_per_minute":{"type":"integer"},"message":{"type":"string"},"documentation_url":{"type":"string","format":"uri"}}},"Reseller":{"type":"object","properties":{"reseller_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"vat_number":{"type":"string"},"address":{"type":"string"},"country_code":{"type":"string"},"status":{"$ref":"#/components/schemas/AccountStatus"},"master_api_key":{"type":"string","description":"Masked, showing only the prefix and the last characters."},"max_tenants":{"type":"integer"},"tenants_count":{"type":"integer"},"remaining_tenant_slots":{"type":"integer"},"rate_limit_per_minute":{"type":"integer"},"webhook_configured":{"type":"boolean"},"billing_settings":{"type":"object","nullable":true},"metadata":{"type":"object","nullable":true},"logo_attached":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}},"ResellerUpdate":{"type":"object","properties":{"name":{"type":"string"},"address":{"type":"string"},"country_code":{"type":"string"},"logo":{"type":"string","description":"The reseller logo, base64 encoded, with or without a data URI prefix. PNG or JPEG, under 1 MB. It replaces the platform logo on the PDFs of every tenant this reseller manages."},"logo_content_type":{"type":"string","enum":["image/png","image/jpeg"],"description":"Media type of the logo. Defaults to image/png."},"logo_filename":{"type":"string","description":"Optional file name kept with the logo."},"metadata":{"type":"object","description":"Free-form reseller settings. The promotion key drives the invitation shown to counterparties on documents and emails: {\"promotion\": {\"name\": \"Your brand\", \"url\": \"https://your.site\", \"enabled\": true}}. Set enabled to false to switch it off for every tenant this reseller manages."}}},"ResellerTenantInput":{"type":"object","required":["company_name","vat_number","company_type","address"],"properties":{"company_name":{"type":"string"},"vat_number":{"type":"string"},"company_type":{"$ref":"#/components/schemas/CompanyType"},"address":{"type":"string"},"email":{"type":"string","format":"email","description":"Optional; a managed tenant may have no email of its own."},"country_code":{"type":"string"},"reseller_reference":{"type":"string","description":"Your own identifier for this tenant, echoed back on reads."},"rate_limit_per_minute":{"type":"integer"}}}}}}