{"openapi":"3.1.2","jsonSchemaDialect":"https://json-schema.org/draft/2020-12/schema","info":{"title":"/dev/einvoice API","version":"0.1.0","summary":"German E-Rechnung compliance as a standalone API.","description":"The `/dev/einvoice` API stores exact immutable XML sources and validates\nthem asynchronously against explicitly selected, immutable validation\npolicies. It is the networked control plane; the isolated document\nprocessor and its implementation libraries are not exposed publicly.\n\n## Authentication\n\nEvery `/einvoice/v1` machine API request requires a PS256-signed, at-most-five-minute RFC\n9068 `at+jwt` access token obtained with the client-credentials grant and a\nfresh signed RFC 9449 DPoP proof.\nThe token must carry the standardized `client_id` claim. The two\nschemes appear in the same OpenAPI Security Requirement Object and are\ntherefore cumulative, not alternatives. Bearer presentation is rejected.\nOrganization and project scope are derived from the authenticated principal\nand never accepted from a request body or query parameter.\nThe separate `/einvoice/console/v1` human management API accepts only the\ndedicated `developers.einvoice.d0.eu` BFF Bearer profile. Identity membership\nis checked against the signed current roster; product permissions are explicit\nlocal grants. Human tokens never authorize invoice operations.\nThe isolated test deployment uses only `https://api.test.d0.eu/einvoice`,\nthe `developers.einvoice.test.d0.eu` human BFF client, its own signed identity\nrosters, database and object store. The fixed `/einvoice/explorer/v1` human\nworkflow uses synthetic XML and the same real asynchronous validator as the\ntest machine API. Test issuance and external delivery are unavailable.\n\n## Exact bytes\n\nXML uploads use a positive `Content-Length` and exactly one RFC 9530\n`Content-Digest` member with SHA-256. The server verifies both values while\nstoring the body and commits metadata only after the exact byte count and\ndigest match. Content codings, transfer codings, redirects, and server-side\nsubstitutions are forbidden at this boundary. Uploading stores bytes; it\ndoes not imply that the XML is well formed or compliant.\n\n## Idempotency\n\nEvery mutating request requires a client-generated `Idempotency-Key`. Keys\nare scoped to the authenticated project and operation route. The server\nfingerprints the method, canonical target, representation media type,\nrelevant integrity headers, and exact request body. Once a request crosses\nits durable commit boundary, an exact replay returns the originally stored\nstatus, body, `Location`, and `ETag` even when the referenced operation has\nsubsequently advanced. Clients use the returned `Location` to fetch current\nstate.\n\nReusing a retained key with a different fingerprint returns\n`422 idempotency-key-reused`. A concurrent exact replay whose first request\nhas not reached a durable outcome returns `409 request-in-progress` with a\nbounded `Retry-After`. Authentication, TLS, rate-limit, and transport\nfailures before the commit boundary do not consume the key; an uncertain\nclient retries with the same key. A fresh key represents a fresh requested\noperation even when its JSON fields match an earlier request.\n\n## Asynchronous validation\n\nValidation states advance monotonically from `queued` to `running`, then to\nexactly one immutable terminal state: `succeeded` or `failed`. Internal\nretries never move a public operation backwards. `succeeded` means the\nvalidator completed and produced evidence; the invoice may still be invalid\n(`result.valid: false`). `failed` is reserved for processing failures that\nprevented a validation result.\n\nPolling clients should send `If-None-Match`, honor `Retry-After`, and follow\n`Location`. Every observable state transition changes the strong `ETag`.\nOnce terminal, the representation and its `ETag` are immutable.\n\n## Errors\n\nError responses use bounded RFC 9457 `application/problem+json`. The\nproblem `type` is the stable machine-readable discriminator. Prose fields\nand validation messages must never echo invoice values or processor\ndiagnostics derived from an uploaded document.\n","contact":{"name":"/dev/null GmbH","url":"https://d0.eu","email":"api@d0.eu"},"license":{"name":"Proprietary","identifier":"LicenseRef-devnull-proprietary"}},"servers":[{"url":"https://api.d0.eu/einvoice/v1"}],"paths":{"/documents":{"post":{"operationId":"createDocument","summary":"Store one immutable XML source","description":"Stores the exact request body as a validation-only document. The body is\nnot normalized, transcoded, parsed, or validated by this operation.\n`Content-Length` is the exact byte count, not a character count, and the\nsole `Content-Digest` value is computed over those same transmitted\nrepresentation bytes.\n\nAn exact `Idempotency-Key` replay returns the original `201` response\nverbatim. Reusing the key for different bytes, headers, media type, or\ntarget is `422`; a still-running exact replay is `409`. Missing length is\n`411`, an oversized body is `413`, and a count or digest mismatch is\n`400`. The connection is closed after a body-integrity failure so that\nunread or surplus bytes cannot become another request.\n","tags":["documents"],"security":[{"oauth2ClientCredentials":["einvoice.documents:write"],"dpopProof":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"},{"$ref":"#/components/parameters/UploadContentLength"},{"$ref":"#/components/parameters/UploadContentDigest"}],"requestBody":{"required":true,"content":{"application/xml":{"schema":{"type":"string","format":"binary","contentMediaType":"application/xml","description":"Exact, unencoded XML representation bytes."}}}},"responses":{"201":{"description":"The exact bytes were verified and durably stored.","headers":{"Location":{"$ref":"#/components/headers/DocumentLocation"},"ETag":{"$ref":"#/components/headers/StrongETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"411":{"$ref":"#/components/responses/LengthRequired"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"$ref":"#/components/responses/UnprocessableContent"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"},"default":{"$ref":"#/components/responses/UnexpectedProblem"}}}},"/documents/{documentId}":{"parameters":[{"$ref":"#/components/parameters/DocumentId"}],"get":{"operationId":"getDocument","summary":"Fetch immutable document metadata","description":"Returns exact-byte metadata, never the XML body or object-store\ncoordinates. A document outside the authenticated project is reported as\n`404`. Expired validation-only content is reported as `410` and cannot be\nused to create a new validation operation.\n","tags":["documents"],"security":[{"oauth2ClientCredentials":["einvoice.documents:read"],"dpopProof":[]}],"parameters":[{"$ref":"#/components/parameters/IfNoneMatch"}],"responses":{"200":{"description":"Immutable metadata for the exact stored source.","headers":{"ETag":{"$ref":"#/components/headers/StrongETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"304":{"$ref":"#/components/responses/NotModified"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"410":{"$ref":"#/components/responses/Gone"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"},"default":{"$ref":"#/components/responses/UnexpectedProblem"}}}},"/validation-operations":{"post":{"operationId":"createValidationOperation","summary":"Queue validation against an explicit pinned policy","description":"Creates durable work for one immutable XML document and one explicit\nvalidation-policy id. The policy id resolves to a frozen manifest before\nthe operation is committed; retries and worker attempts never select a\nnewer policy, validator, or ruleset.\n\nThe response is always the original queued snapshot for an exact\n`Idempotency-Key` replay, even if the operation has since become terminal.\nFetch `Location` for current state. A reused key with a different exact\nJSON representation is `422`; an exact replay still being committed is\n`409` with `Retry-After`. Duplicate JSON names, unknown members, explicit\nnulls, trailing JSON values, unavailable policies, expired documents, and\ncross-project references are rejected before work is queued. The exact\nUTF-8 JSON representation, including insignificant whitespace, is limited\nto 8192 bytes; a larger representation is `413`. HTTP transfer framing\nis decoded before fingerprinting and is not part of the representation;\nrepresentation content codings remain unsupported.\n","tags":["validation-operations"],"security":[{"oauth2ClientCredentials":["einvoice.validations:write"],"dpopProof":[]}],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"x-d0-maximum-representation-bytes":8192,"schema":{"$ref":"#/components/schemas/ValidationOperationCreate"}}}},"responses":{"202":{"description":"Validation was durably queued, or this is an exact replay.","headers":{"Location":{"$ref":"#/components/headers/ValidationOperationLocation"},"ETag":{"$ref":"#/components/headers/StrongETag"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationOperationQueued"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"$ref":"#/components/responses/Gone"},"413":{"$ref":"#/components/responses/PayloadTooLarge"},"415":{"$ref":"#/components/responses/UnsupportedMediaType"},"422":{"$ref":"#/components/responses/UnprocessableContent"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"},"default":{"$ref":"#/components/responses/UnexpectedProblem"}}}},"/validation-operations/{validationOperationId}":{"parameters":[{"$ref":"#/components/parameters/ValidationOperationId"}],"get":{"operationId":"getValidationOperation","summary":"Fetch current validation state","description":"Returns the current monotonic state. `Location` remains the canonical\noperation URI for its lifetime. `Retry-After` is present while state is\n`queued` or `running` and absent once terminal. Send `If-None-Match` to\nreceive `304` when no observable transition occurred. The strong `ETag`\nchanges at every transition and becomes permanent at `succeeded` or\n`failed`.\n","tags":["validation-operations"],"security":[{"oauth2ClientCredentials":["einvoice.validations:read"],"dpopProof":[]}],"parameters":[{"$ref":"#/components/parameters/IfNoneMatch"}],"responses":{"200":{"description":"Current durable validation state.","x-d0-wire-variants":{"queued":"$response.body#/status == 'queued'","running":"$response.body#/status == 'running'","succeeded":"$response.body#/status == 'succeeded'","failed":"$response.body#/status == 'failed'"},"headers":{"Location":{"$ref":"#/components/headers/ValidationOperationLocation"},"ETag":{"$ref":"#/components/headers/StrongETag"},"Retry-After":{"$ref":"#/components/headers/OptionalRetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationOperation"}}}},"304":{"$ref":"#/components/responses/OperationNotModified"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"},"default":{"$ref":"#/components/responses/UnexpectedProblem"}}}},"/validation-operations/{validationOperationId}/result":{"parameters":[{"$ref":"#/components/parameters/ValidationOperationId"}],"get":{"operationId":"getValidationResult","summary":"Fetch an immutable validation result","description":"Exists only after the operation succeeds. A queued or running operation,\nor a failed operation that can never produce a result, returns `409` with\na stable problem type. The result contains exact source identity, the\nfrozen policy manifest, processor and validator components, ruleset\nartifacts, and their SHA-256 digests.\n\n`valid: false` is a normal `200` result proving that validation completed;\nit is never represented as a failed operation or a problem response.\n","tags":["validation-operations"],"security":[{"oauth2ClientCredentials":["einvoice.validations:read"],"dpopProof":[]}],"parameters":[{"$ref":"#/components/parameters/IfNoneMatch"}],"responses":{"200":{"description":"Immutable completed validation evidence.","x-d0-wire-variants":{"valid":["$response.body#/valid == true"],"invalid-recognized":["$response.body#/valid == false","$response.body#/syntax != 'unknown'"],"invalid-unknown":["$response.body#/valid == false","$response.body#/syntax == 'unknown'"]},"headers":{"ETag":{"$ref":"#/components/headers/StrongETag"},"Content-Digest":{"$ref":"#/components/headers/Sha256ContentDigest"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationResult"}}}},"304":{"$ref":"#/components/responses/NotModified"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"},"default":{"$ref":"#/components/responses/UnexpectedProblem"}}}},"/validation-policies":{"get":{"operationId":"listValidationPolicies","summary":"List validation policies","description":"Lists immutable policy manifests visible to the authenticated project.\n`available` and `deprecated` policies may be selected for new operations;\n`withdrawn` policies remain discoverable for historical evidence but are\nrejected by new validation requests. Pagination order is stable for the\nlifetime of a cursor.\n","tags":["validation-policies"],"security":[{"oauth2ClientCredentials":["einvoice.policies:read"],"dpopProof":[]}],"parameters":[{"$ref":"#/components/parameters/PageLimit"},{"$ref":"#/components/parameters/PageCursor"},{"$ref":"#/components/parameters/IfNoneMatch"}],"responses":{"200":{"description":"One bounded page of validation policies.","x-d0-wire-variants":{"last-page":[{"context":"$response.body","condition":"$[?(!@.nextCursor)]","type":"jsonpath"}],"next-page":[{"context":"$response.body","condition":"$[?(@.nextCursor)]","type":"jsonpath"}]},"headers":{"ETag":{"$ref":"#/components/headers/StrongETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationPolicyPage"}}}},"304":{"$ref":"#/components/responses/NotModified"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"},"default":{"$ref":"#/components/responses/UnexpectedProblem"}}}},"/validation-policies/{validationPolicyId}":{"parameters":[{"$ref":"#/components/parameters/ValidationPolicyId"}],"get":{"operationId":"getValidationPolicy","summary":"Fetch one pinned validation policy","description":"Returns a discoverable policy and the digest of its canonical immutable\nmanifest. Lifecycle status may later change to prevent new selections,\nbut the id, version, manifest digest, accepted syntax/profile set, and\ncomponent identities never change.\n","tags":["validation-policies"],"security":[{"oauth2ClientCredentials":["einvoice.policies:read"],"dpopProof":[]}],"parameters":[{"$ref":"#/components/parameters/IfNoneMatch"}],"responses":{"200":{"description":"One validation policy.","headers":{"ETag":{"$ref":"#/components/headers/StrongETag"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationPolicy"}}}},"304":{"$ref":"#/components/responses/NotModified"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalServerError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"},"default":{"$ref":"#/components/responses/UnexpectedProblem"}}}}},"components":{"securitySchemes":{"oauth2ClientCredentials":{"type":"oauth2","description":"Organization-bound, DPoP-bound OAuth 2.0 access token obtained by a\nconfidential client authenticated with `private_key_jwt`. Present it\nwith the `DPoP` authorization scheme, never `Bearer`. Private\norganization UUID binds the lookup to one organization. The exact token\n`(issuer, subject, client_id)` tuple must resolve to an enabled local\ndatabase principal, which supplies the project. A project claim is not\nrequired; if present, it must match that binding. Effective scopes are\nintersected with the principal's registered scopes. The access token is a PS256-signed\nRFC 9068 `at+jwt`; its DPoP proof key is validated against `cnf.jkt` per\nrequest and is deliberately not pinned as durable principal identity.\n","flows":{"clientCredentials":{"tokenUrl":"https://auth.d0.eu/oauth2/token","scopes":{"einvoice.documents:write":"Store immutable validation sources.","einvoice.documents:read":"Read validation-source metadata.","einvoice.validations:write":"Create durable validation operations.","einvoice.validations:read":"Read validation operations and results.","einvoice.policies:read":"Discover validation policies."}}}},"dpopProof":{"type":"apiKey","in":"header","name":"DPoP","description":"Fresh RFC 9449 proof JWT bound to this request method, external target\nURI, access-token hash, and the access token's `cnf.jkt`. The protected\nresource accepts only FAPI algorithms `PS256` and `ES256`, rejects proof\nreplay across replicas, and publishes RFC 9728 metadata at\n`https://api.d0.eu/.well-known/oauth-protected-resource/einvoice`.\n","x-d0-client-middleware":{"kind":"per-request-dpop-proof","authorization-scheme":"DPoP","retry-policy":"regenerate-proof-preserve-idempotency-key"}}},"responses":{"UnexpectedProblem":{"description":"Any other bounded 4xx or 5xx RFC 9457 response.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"ServiceUnavailable":{"description":"A required durable platform dependency is temporarily unavailable.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"InternalServerError":{"description":"Unexpected internal failure with no sensitive diagnostics.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"TooManyRequests":{"description":"Project or client rate limit was exceeded.","headers":{"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"NotFound":{"description":"Resource does not exist in the authenticated project.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"Forbidden":{"description":"The authenticated client lacks a required scope.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"Unauthorized":{"description":"OAuth token or its required DPoP proof is absent, invalid, expired, or replayed.","headers":{"WWW-Authenticate":{"description":"DPoP challenge with supported algorithms and RFC 9728 metadata location.","required":true,"schema":{"type":"string","minLength":1,"maxLength":1024}}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"NotModified":{"description":"The selected representation has the supplied entity tag.","headers":{"ETag":{"$ref":"#/components/headers/StrongETag"}}},"BadRequest":{"description":"Malformed request, headers, query, JSON, or byte-integrity failure.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"Conflict":{"description":"Current resource or idempotency state conflicts with the request. Common\ntypes include `request-in-progress`, `result-not-ready`, and\n`operation-failed`.\n","headers":{"Retry-After":{"$ref":"#/components/headers/OptionalRetryAfter"}},"content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"OperationNotModified":{"description":"Operation representation is unchanged.","x-d0-wire-variants":{"retryable":["$response.header.Retry-After != null"],"terminal":["$response.header.Retry-After == null"]},"headers":{"Location":{"$ref":"#/components/headers/ValidationOperationLocation"},"ETag":{"$ref":"#/components/headers/StrongETag"},"Retry-After":{"$ref":"#/components/headers/OptionalRetryAfter"}}},"UnprocessableContent":{"description":"The well-formed request cannot be accepted. Common types include\n`idempotency-key-reused`, `validation-policy-unavailable`, and\n`document-not-validatable`.\n","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"UnsupportedMediaType":{"description":"Content-Type, charset parameter, or content coding is unsupported.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"PayloadTooLarge":{"description":"Declared or observed content exceeds this endpoint's exact representation limit.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"Gone":{"description":"Validation-only source bytes have expired and are unavailable.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}},"LengthRequired":{"description":"A canonical positive Content-Length is required for this upload.","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/ProblemDetails"}}}}},"schemas":{"ProblemDetails":{"type":"object","additionalProperties":false,"description":"Bounded RFC 9457 problem details with one safe extension.","required":["type","title","status"],"properties":{"type":{"type":"string","format":"uri","pattern":"^https://api\\.d0\\.eu/einvoice/problems/[a-z0-9-]{1,96}$","minLength":37,"maxLength":2048,"description":"Stable machine-readable problem-type URI."},"title":{"type":"string","minLength":1,"maxLength":256},"status":{"type":"integer","format":"int32","minimum":400,"maximum":599},"detail":{"type":"string","minLength":1,"maxLength":8192},"instance":{"type":"string","format":"uri-reference","minLength":1,"maxLength":2048},"invalidParameters":{"type":"array","maxItems":100,"description":"Safe structural request errors; values are never echoed.","items":{"$ref":"#/components/schemas/InvalidParameter"}}}},"InvalidParameter":{"type":"object","additionalProperties":false,"required":["name","reason"],"properties":{"name":{"type":"string","minLength":1,"maxLength":256},"reason":{"type":"string","minLength":1,"maxLength":1024}}},"ValidationPolicy":{"type":"object","additionalProperties":false,"description":"Discoverable lifecycle metadata plus an immutable canonical policy\nmanifest. Lifecycle `status` may change; every other field is frozen.\n","required":["schema","id","name","version","status","manifestSha256","manifestContentDigest","acceptedSyntaxes","profiles","validator","rulesets","publishedAt"],"properties":{"schema":{"type":"string","const":"d0.einvoice.validation-policy.v1","minLength":32,"maxLength":32},"id":{"$ref":"#/components/schemas/ValidationPolicyId"},"name":{"type":"string","minLength":1,"maxLength":256},"description":{"type":"string","minLength":1,"maxLength":2048},"version":{"type":"string","minLength":1,"maxLength":128},"status":{"type":"string","enum":["available","deprecated","withdrawn"],"minLength":9,"maxLength":10},"manifestSha256":{"$ref":"#/components/schemas/Sha256Hex"},"manifestContentDigest":{"$ref":"#/components/schemas/Sha256ContentDigest"},"acceptedSyntaxes":{"type":"array","minItems":1,"maxItems":2,"uniqueItems":true,"items":{"type":"string","enum":["ubl","cii"],"minLength":3,"maxLength":3}},"profiles":{"type":"array","minItems":1,"maxItems":16,"uniqueItems":true,"items":{"type":"string","minLength":1,"maxLength":2048}},"validator":{"allOf":[{"$ref":"#/components/schemas/EvidenceComponent"},{"type":"object","required":["kind"],"properties":{"kind":{"const":"validator"}}}]},"rulesets":{"type":"array","description":"Ordered policy evidence. The first component identifies the primary runtime ruleset; later components identify additional immutable provenance artifacts required by the policy.","minItems":1,"maxItems":16,"uniqueItems":true,"items":{"allOf":[{"$ref":"#/components/schemas/EvidenceComponent"},{"type":"object","required":["kind"],"properties":{"kind":{"const":"ruleset"}}}]}},"publishedAt":{"$ref":"#/components/schemas/Timestamp"}}},"Timestamp":{"type":"string","format":"date-time","description":"RFC 3339 timestamp with an explicit UTC offset.","minLength":20,"maxLength":64},"EvidenceComponent":{"type":"object","additionalProperties":false,"description":"Version and SHA-256 identity of one executed or loaded artifact.","required":["kind","name","version","artifactSha256","artifactContentDigest"],"properties":{"kind":{"type":"string","enum":["processor","validator","ruleset"],"minLength":7,"maxLength":9},"name":{"type":"string","minLength":1,"maxLength":256},"version":{"type":"string","minLength":1,"maxLength":256},"artifactSha256":{"$ref":"#/components/schemas/Sha256Hex"},"artifactContentDigest":{"$ref":"#/components/schemas/Sha256ContentDigest"}}},"Sha256ContentDigest":{"type":"string","description":"Canonical single-member RFC 9530 SHA-256 Content-Digest value.","pattern":"^sha-256=:[A-Za-z0-9+/]{43}=:$","minLength":54,"maxLength":54},"Sha256Hex":{"type":"string","description":"Lowercase hexadecimal SHA-256 digest.","pattern":"^[0-9a-f]{64}$","minLength":64,"maxLength":64},"ValidationPolicyId":{"type":"string","description":"Opaque id pinning exactly one immutable policy manifest.","pattern":"^vpol_[A-Za-z0-9]{20,80}$","minLength":25,"maxLength":85},"ValidationPolicyPage":{"type":"object","additionalProperties":false,"required":["schema","items"],"properties":{"schema":{"type":"string","const":"d0.einvoice.validation-policy-page.v1","minLength":37,"maxLength":37},"items":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/ValidationPolicy"}},"nextCursor":{"type":"string","minLength":1,"maxLength":1024}}},"ValidationResult":{"type":"object","additionalProperties":false,"description":"Immutable evidence for one completed validation. Invalid XML or an\ninvoice that violates the selected policy is represented by\n`valid: false`, at least one error issue, and a successful operation.\n","required":["schema","id","operationId","source","validationPolicy","valid","syntax","validatedAt","evidence","issues"],"properties":{"schema":{"type":"string","const":"d0.einvoice.validation-result.v1","minLength":32,"maxLength":32},"id":{"$ref":"#/components/schemas/ValidationResultId"},"operationId":{"$ref":"#/components/schemas/ValidationOperationId"},"source":{"$ref":"#/components/schemas/ValidationSourceEvidence"},"validationPolicy":{"$ref":"#/components/schemas/PinnedValidationPolicyEvidence"},"valid":{"type":"boolean"},"syntax":{"type":"string","enum":["ubl","cii","unknown"],"minLength":3,"maxLength":7},"profile":{"$ref":"#/components/schemas/ValidationProfile"},"validatedAt":{"$ref":"#/components/schemas/Timestamp"},"evidence":{"$ref":"#/components/schemas/ValidationEvidence"},"issues":{"type":"array","maxItems":1000,"items":{"$ref":"#/components/schemas/ValidationIssue"}}},"oneOf":[{"title":"Valid validation result","x-d0-wire-variant":"valid","required":["valid","profile"],"properties":{"valid":{"const":true},"syntax":{"enum":["ubl","cii"]},"issues":{"not":{"contains":{"type":"object","properties":{"severity":{"const":"error"}},"required":["severity"]}}}}},{"title":"Invalid validation result with recognized syntax","x-d0-wire-variant":"invalid-recognized","required":["valid"],"properties":{"valid":{"const":false},"syntax":{"enum":["ubl","cii"]},"issues":{"minItems":1,"contains":{"type":"object","properties":{"severity":{"const":"error"}},"required":["severity"]}}}},{"title":"Invalid validation result with unknown syntax","x-d0-wire-variant":"invalid-unknown","required":["valid"],"properties":{"valid":{"const":false},"syntax":{"const":"unknown"},"issues":{"minItems":1,"contains":{"type":"object","properties":{"severity":{"const":"error"}},"required":["severity"]}}},"not":{"properties":{"profile":{"$ref":"#/components/schemas/ValidationProfile"}},"required":["profile"]}}]},"ValidationProfile":{"type":"string","minLength":1,"maxLength":2048},"ValidationIssue":{"type":"object","additionalProperties":false,"description":"Structured policy finding. Message and location are bounded, stable, and\ncontain no invoice values, customer data, or attacker-controlled parser\ntext.\n","required":["severity","code","message"],"properties":{"severity":{"type":"string","enum":["error","warning","information"],"minLength":5,"maxLength":11},"code":{"type":"string","description":"Stable ASCII identifier emitted by the pinned compliance ruleset;\nnever free-form diagnostic text or invoice-derived data.\n","minLength":1,"maxLength":256,"pattern":"^[A-Za-z][A-Za-z0-9]*(?:[._:-][A-Za-z0-9]+)*$"},"message":{"type":"string","minLength":1,"maxLength":8192},"location":{"type":"string","minLength":1,"maxLength":8192}}},"ValidationEvidence":{"type":"object","additionalProperties":false,"description":"Exact software and compliance artifacts used for this result.","required":["processor","validator","rulesets"],"properties":{"processor":{"allOf":[{"$ref":"#/components/schemas/EvidenceComponent"},{"type":"object","required":["kind"],"properties":{"kind":{"const":"processor"}}}]},"validator":{"allOf":[{"$ref":"#/components/schemas/EvidenceComponent"},{"type":"object","required":["kind"],"properties":{"kind":{"const":"validator"}}}]},"rulesets":{"type":"array","description":"Ordered immutable compliance evidence. The first component is the primary ruleset that produced the validation finding; later components preserve additional provenance artifacts loaded by that policy.","minItems":1,"maxItems":16,"uniqueItems":true,"items":{"allOf":[{"$ref":"#/components/schemas/EvidenceComponent"},{"type":"object","required":["kind"],"properties":{"kind":{"const":"ruleset"}}}]}}}},"PinnedValidationPolicyEvidence":{"type":"object","additionalProperties":false,"description":"Frozen policy manifest selected before work was queued.","required":["id","version","manifestSha256","manifestContentDigest"],"properties":{"id":{"$ref":"#/components/schemas/ValidationPolicyId"},"version":{"type":"string","minLength":1,"maxLength":128},"manifestSha256":{"$ref":"#/components/schemas/Sha256Hex"},"manifestContentDigest":{"$ref":"#/components/schemas/Sha256ContentDigest"}}},"ValidationSourceEvidence":{"type":"object","additionalProperties":false,"description":"Exact immutable source bytes consumed by the processor.","required":["documentId","mediaType","byteIdentity"],"properties":{"documentId":{"$ref":"#/components/schemas/DocumentId"},"mediaType":{"type":"string","const":"application/xml","minLength":15,"maxLength":15},"byteIdentity":{"$ref":"#/components/schemas/ExactByteIdentity"}}},"ExactByteIdentity":{"type":"object","additionalProperties":false,"description":"Exact immutable identity of one byte representation.","required":["sizeBytes","sha256","contentDigest"],"properties":{"sizeBytes":{"type":"integer","format":"int64","minimum":1,"maximum":20971520},"sha256":{"$ref":"#/components/schemas/Sha256Hex"},"contentDigest":{"$ref":"#/components/schemas/Sha256ContentDigest"}}},"DocumentId":{"type":"string","description":"Opaque public identifier; its characters carry no semantics.","pattern":"^doc_[A-Za-z0-9]{20,80}$","minLength":24,"maxLength":84},"ValidationOperationId":{"type":"string","description":"Opaque public identifier; its characters carry no semantics.","pattern":"^vop_[A-Za-z0-9]{20,80}$","minLength":24,"maxLength":84},"ValidationResultId":{"type":"string","description":"Opaque public identifier; its characters carry no semantics.","pattern":"^vrs_[A-Za-z0-9]{20,80}$","minLength":24,"maxLength":84},"ValidationOperation":{"description":"Durable state discriminated by `status`. Variants are fully closed and\nexplicit null values are never used.\n","oneOf":[{"$ref":"#/components/schemas/ValidationOperationQueued"},{"$ref":"#/components/schemas/ValidationOperationRunning"},{"$ref":"#/components/schemas/ValidationOperationSucceeded"},{"$ref":"#/components/schemas/ValidationOperationFailed"}],"discriminator":{"propertyName":"status","mapping":{"queued":"#/components/schemas/ValidationOperationQueued","running":"#/components/schemas/ValidationOperationRunning","succeeded":"#/components/schemas/ValidationOperationSucceeded","failed":"#/components/schemas/ValidationOperationFailed"}}},"ValidationOperationFailed":{"x-d0-wire-variant":"failed","type":"object","additionalProperties":false,"description":"Immutable terminal processing failure with no validation result.","required":["schema","id","documentId","validationPolicyId","status","requestedAt","updatedAt","startedAt","completedAt","failure"],"properties":{"schema":{"$ref":"#/components/schemas/ValidationOperationSchema"},"id":{"$ref":"#/components/schemas/ValidationOperationId"},"documentId":{"$ref":"#/components/schemas/DocumentId"},"validationPolicyId":{"$ref":"#/components/schemas/ValidationPolicyId"},"status":{"type":"string","const":"failed","minLength":6,"maxLength":6},"requestedAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"startedAt":{"$ref":"#/components/schemas/Timestamp"},"completedAt":{"$ref":"#/components/schemas/Timestamp"},"failure":{"$ref":"#/components/schemas/ValidationOperationFailure"}}},"ValidationOperationFailure":{"type":"object","additionalProperties":false,"description":"Stable public classification without processor diagnostics.","required":["code"],"properties":{"code":{"type":"string","enum":["source-unavailable","processor-unavailable","validation-processing-failed"],"minLength":18,"maxLength":36}}},"ValidationOperationSchema":{"type":"string","const":"d0.einvoice.validation-operation.v1","minLength":35,"maxLength":35},"ValidationOperationSucceeded":{"x-d0-wire-variant":"succeeded","type":"object","additionalProperties":false,"description":"Immutable terminal state proving that validation completed. The linked\nresult may report `valid: false`.\n","required":["schema","id","documentId","validationPolicyId","status","requestedAt","updatedAt","startedAt","completedAt","resultId","resultUri"],"properties":{"schema":{"$ref":"#/components/schemas/ValidationOperationSchema"},"id":{"$ref":"#/components/schemas/ValidationOperationId"},"documentId":{"$ref":"#/components/schemas/DocumentId"},"validationPolicyId":{"$ref":"#/components/schemas/ValidationPolicyId"},"status":{"type":"string","const":"succeeded","minLength":9,"maxLength":9},"requestedAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"startedAt":{"$ref":"#/components/schemas/Timestamp"},"completedAt":{"$ref":"#/components/schemas/Timestamp"},"resultId":{"$ref":"#/components/schemas/ValidationResultId"},"resultUri":{"type":"string","format":"uri-reference","pattern":"^/einvoice/v1/validation-operations/[^/?#]{1,96}/result$","minLength":43,"maxLength":207}}},"ValidationOperationRunning":{"x-d0-wire-variant":"running","type":"object","additionalProperties":false,"description":"Processing has started; internal retries remain in this state.","required":["schema","id","documentId","validationPolicyId","status","requestedAt","updatedAt","startedAt"],"properties":{"schema":{"$ref":"#/components/schemas/ValidationOperationSchema"},"id":{"$ref":"#/components/schemas/ValidationOperationId"},"documentId":{"$ref":"#/components/schemas/DocumentId"},"validationPolicyId":{"$ref":"#/components/schemas/ValidationPolicyId"},"status":{"type":"string","const":"running","minLength":7,"maxLength":7},"requestedAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"},"startedAt":{"$ref":"#/components/schemas/Timestamp"}}},"ValidationOperationQueued":{"x-d0-wire-variant":"queued","type":"object","additionalProperties":false,"description":"Durable work accepted but not yet started by a processor worker.","required":["schema","id","documentId","validationPolicyId","status","requestedAt","updatedAt"],"properties":{"schema":{"$ref":"#/components/schemas/ValidationOperationSchema"},"id":{"$ref":"#/components/schemas/ValidationOperationId"},"documentId":{"$ref":"#/components/schemas/DocumentId"},"validationPolicyId":{"$ref":"#/components/schemas/ValidationPolicyId"},"status":{"type":"string","const":"queued","minLength":6,"maxLength":6},"requestedAt":{"$ref":"#/components/schemas/Timestamp"},"updatedAt":{"$ref":"#/components/schemas/Timestamp"}}},"ValidationOperationCreate":{"type":"object","additionalProperties":false,"description":"Exact immutable source and explicit policy selection.","required":["documentId","validationPolicyId"],"properties":{"documentId":{"$ref":"#/components/schemas/DocumentId"},"validationPolicyId":{"$ref":"#/components/schemas/ValidationPolicyId"}}},"Document":{"type":"object","additionalProperties":false,"description":"Immutable metadata for exact validation-only XML bytes.","required":["schema","id","mediaType","byteIdentity","createdAt","expiresAt"],"properties":{"schema":{"type":"string","const":"d0.einvoice.document.v1","minLength":23,"maxLength":23},"id":{"$ref":"#/components/schemas/DocumentId"},"mediaType":{"type":"string","const":"application/xml","minLength":15,"maxLength":15},"byteIdentity":{"$ref":"#/components/schemas/ExactByteIdentity"},"createdAt":{"$ref":"#/components/schemas/Timestamp"},"expiresAt":{"allOf":[{"$ref":"#/components/schemas/Timestamp"}],"description":"Declared deletion deadline for validation-only source bytes."}}}},"headers":{"RetryAfter":{"description":"Canonical delta-seconds before the next recommended poll.","required":true,"schema":{"type":"integer","format":"int32","minimum":1,"maximum":300,"x-d0-wire-pattern":"^(?:[1-9]|[1-9][0-9]|[12][0-9]{2}|300)$"}},"StrongETag":{"description":"Strong RFC 9110 entity tag. Mutable operation representations receive a\nnew value at every observable state transition; immutable resources keep\nthe same value permanently.\n","required":true,"schema":{"type":"string","pattern":"^\"sha256-[0-9a-f]{64}\"$","minLength":73,"maxLength":73}},"OptionalRetryAfter":{"description":"Canonical delta-seconds while an operation is queued or running. This\nheader is absent for terminal operation representations.\n","required":false,"schema":{"type":"integer","format":"int32","minimum":1,"maximum":300,"x-d0-wire-pattern":"^(?:[1-9]|[1-9][0-9]|[12][0-9]{2}|300)$"}},"Sha256ContentDigest":{"description":"RFC 9530 SHA-256 digest of the exact response content bytes.","required":true,"schema":{"$ref":"#/components/schemas/Sha256ContentDigest"}},"ValidationOperationLocation":{"description":"Relative canonical URI of the durable validation operation.","required":true,"schema":{"type":"string","format":"uri-reference","pattern":"^/einvoice/v1/validation-operations/[^/?#]{1,96}$","maxLength":200}},"DocumentLocation":{"description":"Relative canonical URI of the immutable document metadata.","required":true,"schema":{"type":"string","format":"uri-reference","pattern":"^/einvoice/v1/documents/[^/?#]{1,96}$","maxLength":160}}},"parameters":{"IfNoneMatch":{"name":"If-None-Match","in":"header","required":false,"description":"RFC 9110 entity-tag condition. Send the last strong ETag to avoid\nretransmitting an unchanged representation. Lists and `*` are accepted\naccording to the HTTP field grammar.\n","schema":{"type":"string","minLength":1,"maxLength":512}},"ValidationPolicyId":{"name":"validationPolicyId","in":"path","required":true,"description":"Opaque identifier of one immutable validation-policy manifest.","schema":{"$ref":"#/components/schemas/ValidationPolicyId"}},"PageCursor":{"name":"cursor","in":"query","required":false,"description":"Opaque cursor returned by the preceding page.","schema":{"type":"string","minLength":1,"maxLength":1024}},"PageLimit":{"name":"limit","in":"query","required":false,"description":"Maximum number of policies to return.","schema":{"type":"integer","format":"int32","minimum":1,"maximum":100,"default":50}},"ValidationOperationId":{"name":"validationOperationId","in":"path","required":true,"description":"Opaque public validation-operation identifier.","schema":{"$ref":"#/components/schemas/ValidationOperationId"}},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":true,"description":"Opaque, client-generated, high-entropy key unique to this authenticated\nproject and operation route. It is compared as an exact case-sensitive\nvalue after HTTP field parsing. Use the same key after an uncertain\nresponse; never derive it from invoice data or other PII.\n","schema":{"type":"string","pattern":"^[A-Za-z0-9._~:+/=-]{16,255}$","minLength":16,"maxLength":255}},"DocumentId":{"name":"documentId","in":"path","required":true,"description":"Opaque public document identifier; clients must not parse it.","schema":{"$ref":"#/components/schemas/DocumentId"}},"UploadContentDigest":{"name":"Content-Digest","in":"header","required":true,"description":"Exactly one canonical RFC 9530 SHA-256 member over the representation\nbytes. Other algorithms, dictionaries with multiple members, and\nduplicate field lines are rejected.\n","schema":{"$ref":"#/components/schemas/Sha256ContentDigest"}},"UploadContentLength":{"name":"Content-Length","in":"header","required":true,"description":"Canonical positive decimal byte length of the exact XML representation.\nTransfer-Encoding and conflicting or duplicate lengths are forbidden.\n","schema":{"type":"integer","format":"int64","minimum":1,"maximum":20971520}}}},"x-d0-environment":"production","x-d0-resource":"https://api.d0.eu/einvoice"}