openapi: 3.1.0 info: title: Invoice Invoices Scribo API version: 1.0.0 description: Compliant e-invoice generation. **Phase 1 supports Germany (XRechnung / ZUGFeRD) and the United States (plain PDF) only** — any other sender jurisdiction is rejected with `unsupported_jurisdiction`. The `/api/v1/*` namespace served from `scribo.causaprima.ai` is the public surface — anonymous and rate-limited. The internal `/internal/scribo/*` namespace is used by the Causa Prima web app and MCP server and is not part of this contract. contact: name: Causa Prima url: https://causaprima.ai servers: - url: https://scribo.causaprima.ai description: Production - url: http://localhost:3200 description: Local development (scribo Next.js proxy) tags: - name: Scribo paths: /api/v1/scribo/email-verifications: post: summary: Request a sender email-ownership challenge description: Emails a 6-character verification code (and magic link) to the address. Always returns a uniform 202 — new, returning, throttled, and send-failed callers are indistinguishable (anti-enumeration). Sends are rate-limited per email (resend cooldown + hourly cap). requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RequestVerificationInput' responses: '202': description: Challenge accepted (uniform anti-enumeration shape) content: application/json: schema: $ref: '#/components/schemas/VerificationChallenge' '400': description: Invalid input content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' tags: - Scribo /api/v1/scribo/email-verifications/{id}/redeem: post: summary: Redeem the emailed code for a verification token description: Exchanges the 6-character code for a verification_token, sent as X-Email-Verification-Token on POST /invoices. The token is reusable for ~30 minutes for the same sender email. parameters: - schema: type: string format: uuid description: Challenge UUID required: true name: id in: path requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/RedeemVerificationInput' responses: '200': description: Code accepted content: application/json: schema: $ref: '#/components/schemas/VerificationToken' '400': description: Wrong, expired, or revoked code — uniform verification_invalid across all three causes content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' tags: - Scribo /api/v1/scribo/email-verifications/{id}: get: summary: Verification challenge status snapshot description: Polling fallback for browser flows waiting on the emailed magic link. verification_token is present only when status is `verified`. parameters: - schema: type: string format: uuid description: Challenge UUID required: true name: id in: path responses: '200': description: Challenge status content: application/json: schema: $ref: '#/components/schemas/VerificationSnapshot' tags: - Scribo /api/v1/scribo/email-verifications/{id}/events: get: summary: Verification challenge event stream description: Server-Sent Events stream of challenge status transitions; closes after `verified`. Browser flows use this instead of polling the snapshot endpoint. parameters: - schema: type: string format: uuid description: Challenge UUID required: true name: id in: path responses: '200': description: SSE stream content: text/event-stream: schema: type: string tags: - Scribo components: schemas: VerificationToken: type: object properties: verification_token: type: string expires_at: type: string format: date-time required: - verification_token - expires_at VerificationSnapshot: oneOf: - type: object properties: status: type: string enum: - pending expires_at: type: string required: - status - expires_at - type: object properties: status: type: string enum: - verified verification_token: type: string expires_at: type: string required: - status - verification_token - expires_at - type: object properties: status: type: string enum: - expired required: - status - type: object properties: status: type: string enum: - revoked required: - status ErrorEnvelope: type: object properties: error: type: object properties: code: type: string example: invalid_input message: type: string details: {} required: - code - message required: - error RequestVerificationInput: type: object properties: email: type: string minLength: 3 maxLength: 254 format: email required: - email additionalProperties: false RedeemVerificationInput: type: object properties: code: type: string minLength: 1 maxLength: 64 required: - code additionalProperties: false VerificationChallenge: type: object properties: challenge_id: type: string format: uuid expires_at: type: string format: date-time next_request_allowed_at: type: string format: date-time required: - challenge_id - expires_at - next_request_allowed_at securitySchemes: bearerAuth: type: http scheme: bearer description: Optional API key for elevated quotas. Unauthenticated requests are accepted and rate-limited per IP.