{"openapi":"3.1.0","info":{"title":"Doxnex API","description":"Document Intelligence API — Generate compliant fiscal documents (invoices, credit notes, debit notes, prepayments, receipts, delivery notes) in Factur-X and Peppol UBL formats. 8 languages incl. Arabic bilingual RTL.","termsOfService":"https://doxnex.io/terms","contact":{"name":"AZMORIS Group","url":"https://doxnex.io","email":"support@doxnex.io"},"license":{"name":"Proprietary","url":"https://doxnex.io/license"},"version":"3.1.0"},"servers":[{"url":"http://api.doxnex.io","description":"Generated server url"}],"tags":[{"name":"Admin · Audit Events","description":"ISO 27001 A.12.4.1 audit trail (read-only)"},{"name":"Multi-Factor Authentication","description":"TOTP MFA setup + verify (Sprint 2.6)"},{"name":"Documents","description":"Document generation and retrieval — The core Doxnex API"},{"name":"Account","description":"Self-service registration, recovery, and account management"},{"name":"Articles","description":"Product/service catalog for reusable invoice line items"},{"name":"GDPR","description":"Data privacy compliance — export and erasure"},{"name":"Public Documents","description":"Public shareable document pages — no authentication required"},{"name":"Public Validator","description":"Free e-invoice validation — no authentication required"},{"name":"Reports","description":"Revenue, VAT, DSO, top clients, dashboard summary"},{"name":"API Keys","description":"API key management for document generation access"},{"name":"Group Invitations","description":"Magic-link invitation flow for groups"},{"name":"Admin","description":"Administrative dashboard and analytics"},{"name":"Customers","description":"Customer/recipient management — reusable profiles for documents"},{"name":"Group Aggregations","description":"Cross-tenant analytics for groups (read-only)"},{"name":"Public Invitation","description":"Token-based team invitation accept flow — no auth required"},{"name":"Webhooks","description":"Webhook endpoint management for event notifications"},{"name":"Tenant Groups","description":"Multi-subsidiary group management"},{"name":"Group Ownership Transfer","description":"2-step ownership transfer with 24h hold"},{"name":"Templates","description":"Document template management (Thymeleaf HTML + CSS)"},{"name":"Reconciliation","description":"Universal bank reconciliation (Sprint AI-002)"},{"name":"SIRENE","description":"French company database lookup via GEOREFER"},{"name":"Compliance matrix","description":"Country → primary + secondary format mapping. Read-only."},{"name":"Archive","description":"Document archiving with SHA-256 hash chain verification"},{"name":"Multi-Filiales Admin (Bulk)","description":"Admin-only bulk operations on tenant groups (CSV upload)"},{"name":"Admin · Cert Expiry Watcher","description":"Manual trigger for the daily certificate expiry watcher job (F-5)"},{"name":"Health","description":"Service health and version information"},{"name":"Inbound Webhooks","description":"Inbound webhooks for e-invoices received through a Plateforme Agreee (B2Brouter...)"},{"name":"Billing","description":"Stripe payment integration and subscription management"},{"name":"Document Amendments","description":"Amendment workflow for submitted documents (CHANTIER 7)"},{"name":"Received Invoices","description":"Inbox of invoices received through a Plateforme Agreee (B2Brouter...)"},{"name":"Tenant Tunisia","description":"Per-tenant TTN / El Fatoora configuration"},{"name":"Signature Wallet","description":"Tenant signature method + credentials management (Copie Swiver pure strategy 2026-04-21: DIGIGO, ENTERPRISE_ID_SEAL, ID_TRUST_USB)"},{"name":"Dashboard","description":"Aggregate KPIs for the tenant dashboard"},{"name":"Authentication","description":"Public OTP-based email login"},{"name":"Public Contact","description":"Landing page contact form — no authentication required"},{"name":"Users","description":"Multi-user team management within a company"},{"name":"Public Quote Signing","description":"Online quote acceptance — no authentication required"}],"paths":{"/api/v1/templates/{id}":{"get":{"tags":["Templates"],"summary":"Get template by ID","operationId":"findById","parameters":[{"name":"id","in":"path","description":"Template ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}}}},"put":{"tags":["Templates"],"summary":"Update a template","description":"Partially updates a template. Increments version number.","operationId":"update","parameters":[{"name":"id","in":"path","description":"Template ID","required":true,"schema":{"type":"string","default":""}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateUpdateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}}}},"delete":{"tags":["Templates"],"summary":"Delete a template","description":"Soft-deletes a template (sets active=false).","operationId":"delete","parameters":[{"name":"id","in":"path","description":"Template ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK"}}}},"/api/v1/signature-wallet/ttn-environment":{"put":{"tags":["Signature Wallet"],"summary":"Switch the active TTN environment (TEST / PROD)","operationId":"switchTtnEnvironment","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/ttn-credentials":{"put":{"tags":["Signature Wallet"],"summary":"Set the TTN Elfatoora username + password for TEST or PROD environment","operationId":"updateTtnCredentials","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/method":{"put":{"tags":["Signature Wallet"],"summary":"Configure or change the active signature method and its (encrypted) credentials","operationId":"changeMethod","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/certificate-metadata":{"put":{"tags":["Signature Wallet"],"summary":"Record the metadata of the currently loaded cert","operationId":"recordCertificateMetadata","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/customers/{id}":{"get":{"tags":["Customers"],"summary":"Get customer by ID","operationId":"getById","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Customer found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"404":{"description":"Customer not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}}}},"put":{"tags":["Customers"],"summary":"Update a customer","description":"Partial update — only provided fields are changed.","operationId":"update_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Customer updated","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"404":{"description":"Customer not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}}}},"delete":{"tags":["Customers"],"summary":"Delete a customer","description":"Soft-deletes a customer. Does not affect previously generated documents.","operationId":"delete_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Customer deleted"},"404":{"description":"Customer not found"}}}},"/api/v1/articles/{id}":{"put":{"tags":["Articles"],"summary":"Update an article","operationId":"update_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Article"}}}}}},"delete":{"tags":["Articles"],"summary":"Soft-delete an article","operationId":"delete_2","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}},"/api/v1/api-keys/{id}/revoke":{"put":{"tags":["API Keys"],"summary":"Revoke an API key","description":"Deactivates an API key. It can no longer be used for authentication.","operationId":"revoke","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK"}}}},"/api/v1/account/settings":{"get":{"tags":["Account"],"summary":"Get account settings","description":"Returns the portal settings (company info, VAT rates, invoicing preferences) stored on the server.","operationId":"getSettings","responses":{"200":{"description":"Settings returned","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}},"put":{"tags":["Account"],"summary":"Save account settings","description":"Persists portal settings (company info, VAT rates, invoicing preferences) on the server as a JSON blob.","operationId":"saveSettings","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"Settings saved","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"List all webhook endpoints for current tenant","operationId":"findAll","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/WebhookResponse"}}}}}}},"post":{"tags":["Webhooks"],"summary":"Register a webhook endpoint","description":"Creates a new webhook endpoint. A signing secret is generated automatically.","operationId":"create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}}}}},"/api/v1/webhooks/{id}/test":{"post":{"tags":["Webhooks"],"summary":"Send a test event to a webhook endpoint","operationId":"sendTestEvent","parameters":[{"name":"id","in":"path","description":"Webhook endpoint ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/validators/schematron-suggestion":{"post":{"tags":["schematron-validator-controller"],"operationId":"suggestCorrection","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SchematronSuggestionRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/users/{userId}/regenerate-key":{"post":{"tags":["Users"],"summary":"Regenerate API key for a user (requires OTP action token)","operationId":"regenerateApiKey","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/users/otp/verify":{"post":{"tags":["Users"],"summary":"Verify an OTP code","operationId":"verifyOtp","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/users/otp/request":{"post":{"tags":["Users"],"summary":"Request an OTP code for sensitive actions","operationId":"requestOtp","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/users/invite":{"post":{"tags":["Users"],"summary":"Invite a new team member (OWNER/ADMIN)","operationId":"invite","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/users/invite-by-token":{"post":{"tags":["Users"],"summary":"Invite a new team member via email link (OWNER/ADMIN)","operationId":"inviteByToken","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/transfers/{id}/cancel":{"post":{"tags":["Group Ownership Transfer"],"summary":"Cancel a transfer during the 24h hold","description":"From-user, to-user or current owner may cancel.","operationId":"cancelTransfer","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelTransferRequest"}}}},"responses":{"204":{"description":"No Content"}}}},"/api/v1/transfers/{id}/accept":{"post":{"tags":["Group Ownership Transfer"],"summary":"Accept an ownership transfer (starts 24h hold)","description":"Only the declared to-user can accept.","operationId":"acceptTransfer","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TransferResponse"}}}}}}},"/api/v1/tenant/tunisia/request-production-activation":{"post":{"tags":["Tenant Tunisia"],"summary":"Request TTN production activation","description":"Validates prerequisites server-side. Returns 400 + missing_fields if incomplete, 200 + PENDING_ADMIN_APPROVAL otherwise.","operationId":"requestProductionActivation","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/templates":{"get":{"tags":["Templates"],"summary":"List all templates for current tenant","operationId":"findAll_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TemplateResponse"}}}}}}},"post":{"tags":["Templates"],"summary":"Create a new template","description":"Creates a new Thymeleaf template. Slug must be unique per tenant.","operationId":"create_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}}}}},"/api/v1/signature-wallet":{"get":{"tags":["Signature Wallet"],"summary":"Get the current tenant's signature wallet","operationId":"getWallet","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}},"post":{"tags":["Signature Wallet"],"summary":"Create a PENDING wallet for the current tenant","operationId":"createWallet","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/ttn-submission/retry-after-rejection":{"post":{"tags":["Signature Wallet"],"summary":"After TTN rejection, reset the workflow to NOT_SUBMITTED","operationId":"retryAfterRejection","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/ttn-submission/reject":{"post":{"tags":["Signature Wallet"],"summary":"TTN rejected the submission — record reason","operationId":"rejectTtn","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/ttn-submission/mark-submitted-test":{"post":{"tags":["Signature Wallet"],"summary":"Tenant confirms the TEST email was sent to TTN","operationId":"markTtnSubmittedTest","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/ttn-submission/mark-submitted-prod":{"post":{"tags":["Signature Wallet"],"summary":"Tenant confirms the PROD email was sent to TTN","operationId":"markTtnSubmittedProd","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/ttn-submission/mark-email-generated":{"post":{"tags":["Signature Wallet"],"summary":"Record that the TTN email template has been generated","operationId":"markTtnEmailGenerated","parameters":[{"name":"env","in":"query","required":true,"schema":{"type":"string","enum":["TEST","PROD"]}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/ttn-submission/approve-test":{"post":{"tags":["Signature Wallet"],"summary":"TTN returned TEST credentials — persist them (encrypted)","operationId":"approveTtnTest","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/ttn-submission/approve-prod":{"post":{"tags":["Signature Wallet"],"summary":"TTN returned PROD credentials — persist them (encrypted)","operationId":"approveTtnProd","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/suspend":{"post":{"tags":["Signature Wallet"],"summary":"Suspend the wallet (no sign until re-activated)","operationId":"suspend","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/enterprise-id/mark-email-sent":{"post":{"tags":["Signature Wallet"],"summary":"Tenant confirms Enterprise-ID email was sent to TTN","operationId":"markEnterpriseIdEmailSent","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/enterprise-id/configure-seal-keys":{"post":{"tags":["Signature Wallet"],"summary":"TTN returned SEAL_KEY + SEAL_PIN — persist them (encrypted)","operationId":"configureEnterpriseIdSealKeys","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/signature-wallet/activate":{"post":{"tags":["Signature Wallet"],"summary":"Activate the wallet (PENDING or SUSPENDED → ACTIVE)","operationId":"activate","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/SignatureWalletDto"}}}}}}},"/api/v1/reconciliation/transactions/import":{"post":{"tags":["Reconciliation"],"summary":"Import a bank export file (OFX / QIF / CSV) — auto-detects format","operationId":"importFile","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ImportResult"}}}}}}},"/api/v1/reconciliation/matches/{id}/validate":{"post":{"tags":["Reconciliation"],"summary":"Validate a reconciliation match — marks document PAID and transaction matched","operationId":"validate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ReconciliationMatch"}}}}}}},"/api/v1/reconciliation/matches/{id}/reject":{"post":{"tags":["Reconciliation"],"summary":"Reject a reconciliation match — leaves document and transaction unchanged","operationId":"reject","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ReconciliationMatch"}}}}}}},"/api/v1/reconciliation/compute":{"post":{"tags":["Reconciliation"],"summary":"Run the reconciliation engine against current unpaid invoices and unmatched transactions","operationId":"compute","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ReconciliationMatch"}}}}}}}},"/api/v1/public/validate":{"post":{"tags":["Public Validator"],"summary":"Validate an e-invoice","description":"Upload a PDF (Factur-X/ZUGFeRD) or XML (CII/UBL) file. Returns a detailed validation report with score, checks, and extracted metadata. Files are not stored — processed in memory only. Rate limit: 10 validations per hour per IP.","operationId":"validate_1","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/public/quotes/{viewId}/sign":{"post":{"tags":["Public Quote Signing"],"summary":"Sign a quote","description":"Accept and sign a quote online. Records signer identity, IP, and cryptographic hash.","operationId":"signQuote","parameters":[{"name":"viewId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/public/invitation/{token}/accept":{"post":{"tags":["Public Invitation"],"summary":"Accept the invitation and create the team-member user","operationId":"accept","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Forwarded-For","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/public/contact":{"post":{"tags":["Public Contact"],"summary":"Submit a contact form","description":"Sends the landing-page Scale/Enterprise contact form to the AZMORIS team. Rate limit: 5 submissions per hour per IP.","operationId":"submit","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/public/ai-fix":{"post":{"tags":["Public Validator"],"summary":"AI-powered error correction","description":"Send a validation error to get an AI-generated explanation and corrected XML. Uses Claude Haiku for fast, cost-effective responses. Rate limit: 5 fixes per hour per IP.","operationId":"aiFix","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiFixRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/public/ai-demo":{"post":{"tags":["public-ai-demo-controller"],"operationId":"demoSuggestCorrection","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicDemoRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/mfa/verify":{"post":{"tags":["Multi-Factor Authentication"],"summary":"Verify MFA code on login second step","description":"Validates a 6-digit code. Updates last_verified_at on success. Sprint 2.6-bis : if a valid doxnex_trust cookie is present, the TOTP code check is skipped (sliding window refresh). If the user submits trustDevice=true with a valid code, a doxnex_trust cookie is set with 30-day expiry.","operationId":"verify","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaVerifyRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/mfa/setup":{"post":{"tags":["Multi-Factor Authentication"],"summary":"Initiate MFA setup","description":"Generates a fresh TOTP secret + QR code PNG (base64) for authenticator app scanning. The secret is persisted with is_enabled=false. Caller must POST /enable with a valid code to activate.","operationId":"setup","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/mfa/recovery":{"post":{"tags":["Multi-Factor Authentication"],"summary":"Use a recovery code (authenticator app lost)","description":"Consumes one of the 10 recovery codes generated at MFA enable time. On success, MFA is disabled and the user must re-setup with a fresh secret + new recovery codes.","operationId":"useRecovery","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecoveryCodeRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/mfa/enable":{"post":{"tags":["Multi-Factor Authentication"],"summary":"Enable MFA after verifying first code","description":"Verifies the 6-digit code from the authenticator app and, on success, activates MFA + generates 10 recovery codes returned ONCE.","operationId":"enable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaCodeRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/mfa/disable":{"post":{"tags":["Multi-Factor Authentication"],"summary":"Disable MFA after verifying current code","operationId":"disable","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MfaCodeRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/invitations/reject":{"post":{"tags":["Group Invitations"],"summary":"Reject a group invitation","description":"Auth required. Acting user's email must match the invited email.","operationId":"rejectInvitation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInvitationRequest"}}},"required":true},"responses":{"204":{"description":"No Content"}}}},"/api/v1/invitations/accept":{"post":{"tags":["Group Invitations"],"summary":"Accept a group invitation (creates membership)","description":"Auth required. Acting user's email must match the invited email.","operationId":"acceptInvitation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInvitationRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/MembershipResponse"}}}}}}},"/api/v1/inbound/b2brouter":{"post":{"tags":["Inbound Webhooks"],"summary":"Inbound webhook from B2Brouter","description":"Called by B2Brouter when a new invoice is received for a tenant. Signature is verified with the shared secret if configured.","operationId":"handleB2BRouter","parameters":[{"name":"X-B2Brouter-Signature","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-Doxnex-Tenant","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/groups":{"get":{"tags":["Tenant Groups"],"summary":"List groups visible to the caller (cursor-paginated)","description":"Sprint 2.3 — keyset pagination. Pass `cursor` from the previous response's `nextCursor` field to fetch the next page. `limit` defaults to 20, max 100. Treat the cursor value as opaque — do not parse it.","operationId":"listGroups","parameters":[{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","maximum":100,"minimum":1}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PagedResponseGroupResponse"}}}}}},"post":{"tags":["Tenant Groups"],"summary":"Create a tenant group","description":"Caller becomes GROUP_OWNER. Returns 201 + Location header.","operationId":"createGroup","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateGroupRequest"}}},"required":true},"responses":{"201":{"description":"Group created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"400":{"description":"Validation error","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"401":{"description":"Authentication required","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}}}}},"/api/v1/groups/{id}/tenants/{tenantId}":{"post":{"tags":["Tenant Groups"],"summary":"Attach a tenant to the group","description":"Caller must be GROUP_OWNER or GROUP_ADMIN of the target group.","operationId":"addTenant","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"}}},"delete":{"tags":["Tenant Groups"],"summary":"Detach a tenant from the group","operationId":"removeTenant","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"}}}},"/api/v1/groups/{groupId}/transfers":{"get":{"tags":["Group Ownership Transfer"],"summary":"List ownership transfers of a group (cursor-paginated, admin only)","description":"Caller must be GROUP_OWNER or GROUP_ADMIN. Optional ?status= filter (INITIATED / ACCEPTED / COMPLETED / CANCELLED / REJECTED / EXPIRED). Cursor pattern aligned with Sprint 2.3.","operationId":"listTransfers","parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","maximum":100,"minimum":1}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List returned (may be empty)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PagedResponseTransferResponse"}}}},"400":{"description":"Invalid cursor or limit out of bounds","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PagedResponseTransferResponse"}}}},"403":{"description":"Caller is not a member or is GROUP_VIEWER","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PagedResponseTransferResponse"}}}}}},"post":{"tags":["Group Ownership Transfer"],"summary":"Initiate ownership transfer","description":"Caller must be current GROUP_OWNER. Target user must be GROUP_ADMIN of the group.","operationId":"initiateTransfer","parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitiateTransferRequest"}}},"required":true},"responses":{"201":{"description":"Transfer initiated, awaiting acceptance","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TransferResponse"}}}},"403":{"description":"Caller is not the owner","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TransferResponse"}}}},"409":{"description":"Active transfer already exists or target is not GROUP_ADMIN","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TransferResponse"}}}}}}},"/api/v1/groups/{groupId}/invitations":{"get":{"tags":["Group Invitations"],"summary":"List invitations of a group (cursor-paginated, admin only)","description":"Caller must be GROUP_OWNER or GROUP_ADMIN. Optional ?status= filter (PENDING / ACCEPTED / REJECTED / EXPIRED / REVOKED). Cursor pagination follows the same opaque-token pattern as GET /api/v1/groups.","operationId":"listInvitations","parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","maximum":100,"minimum":1}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List returned (may be empty)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PagedResponseInvitationResponse"}}}},"400":{"description":"Invalid cursor or limit out of bounds","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PagedResponseInvitationResponse"}}}},"403":{"description":"Caller is not a member or is GROUP_VIEWER","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PagedResponseInvitationResponse"}}}}}},"post":{"tags":["Group Invitations"],"summary":"Send a group invitation by email","operationId":"sendInvitation","parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendInvitationRequest"}}},"required":true},"responses":{"201":{"description":"Invitation sent","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InvitationResponse"}}}},"400":{"description":"Validation error","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InvitationResponse"}}}},"403":{"description":"Caller is not OWNER/ADMIN","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InvitationResponse"}}}},"409":{"description":"Pending invitation already exists or invitee is a member","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InvitationResponse"}}}}}}},"/api/v1/gdpr/consent/{tenantId}":{"post":{"tags":["GDPR"],"summary":"Record data processing consent","operationId":"recordConsent","parameters":[{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/documents/{quoteId}/convert":{"post":{"tags":["Documents"],"summary":"Convert a quote to an invoice","operationId":"convertQuoteToInvoice","parameters":[{"name":"quoteId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GenerateDocumentResponse"}}}}}}},"/api/v1/documents/{id}/withholding-certificate":{"get":{"tags":["Documents"],"summary":"Download withholding tax certificate PDF","operationId":"downloadWithholdingCertificate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}},"post":{"tags":["Documents"],"summary":"Generate withholding tax certificate","description":"Generates a Certificat de Retenue a la Source for Tunisian invoices with withholding tax.","operationId":"generateWithholdingCertificate","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/documents/{id}/submit":{"post":{"tags":["Documents"],"summary":"Submit document to ASP/PA for fiscal validation","operationId":"submitToProvider","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/documents/{id}/submit-ttn":{"post":{"tags":["Documents"],"summary":"Submit a TEIF document to Tunisie TradeNet (El Fatoora)","description":"Shortcut for POST /{id}/submit with provider=\"ttn\". The document must have been generated with compliance=\"teif\". Returns a stub response until TTN production credentials are configured (doxnex.tunisia.ttn.enabled=true + doxnex.tunisia.ttn.url/api-key/sender-id).","operationId":"submitToTtn","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/documents/{id}/sign-teif":{"post":{"tags":["Documents"],"summary":"Produce a XAdES-B signed TEIF XML for a document","description":"Standalone signature endpoint (no TTN submit). Uses the tenant's SignatureWallet via TenantAwareSignatureOrchestrator. Returns SHA-256 of the signed XML + wallet metadata. Useful for smoke-testing the crypto pipeline or for an admin demo of the signing flow.","operationId":"signTeif","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/documents/{id}/send":{"post":{"tags":["Documents"],"summary":"Send document by email","operationId":"sendByEmail","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/documents/{id}/secondary-format":{"post":{"tags":["Documents"],"summary":"Generate secondary compliance XML for cross-border","description":"Generates a secondary XML in the client's country format (e.g. Peppol UBL for a French issuer billing an Omani client).","operationId":"generateSecondaryFormat","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/documents/{id}/amend":{"post":{"tags":["Document Amendments"],"summary":"Amend a previously-submitted document","description":"Creates a new DRAFT document that references the original, with an incremented amendment_number. Reason is required (20-512 chars). Returns 409 if the document is not in an amendable state.","operationId":"amend","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AmendmentRequestDto"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DocumentMetadata"}}}}}}},"/api/v1/documents/validate":{"post":{"tags":["Documents"],"summary":"Validate document data before generation","description":"Runs 10 deterministic validation rules against the document data payload. Returns individual check results with severity levels (ERROR, WARNING, INFO). No document is generated — this is a dry-run validation only. Typical response < 100ms.","operationId":"validate_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateDocumentRequest"}}},"required":true},"responses":{"200":{"description":"Validation completed (check 'valid' field for pass/fail)","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ValidationResult"}}}},"400":{"description":"Invalid request payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ValidationResult"}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ValidationResult"}}}}}}},"/api/v1/documents/preview":{"post":{"tags":["Documents"],"summary":"Render an in-memory PDF preview","description":"Runs the render pipeline (template + Thymeleaf + PDF) against the supplied data and streams back the resulting PDF. NO persistence happens: no DocumentMetadata row, no MinIO upload, no document-number increment, no hash chain. Intended for the split-view live preview. The real /generate endpoint is still the only path that materialises a document on the tenant's ledger.","operationId":"preview","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDocumentRequest"}}},"required":true},"responses":{"200":{"description":"PDF bytes streamed as application/pdf","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}},"400":{"description":"Invalid request payload","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}}},"/api/v1/documents/import":{"post":{"tags":["Documents"],"summary":"Import articles/items from Excel or CSV","description":"Parses an xlsx, xls, or csv file with multilingual column headers and returns structured row data.","operationId":"importFile_1","requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/documents/generate":{"post":{"tags":["Documents"],"summary":"Generate a document","description":"Generates a PDF document from a template and data payload. Pipeline: validate -> render HTML -> convert PDF -> store -> hash chain -> respond. Returns document ID, presigned download URL, and NF525 hash.","operationId":"generate","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDocumentRequest"}}},"required":true},"responses":{"201":{"description":"Document generated successfully","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GenerateDocumentResponse"}}}},"400":{"description":"Invalid request payload","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GenerateDocumentResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GenerateDocumentResponse"}}}},"404":{"description":"Template not found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GenerateDocumentResponse"}}}},"429":{"description":"Rate limit or quota exceeded","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GenerateDocumentResponse"}}}}}}},"/api/v1/customers":{"get":{"tags":["Customers"],"summary":"List customers","description":"Paginated list of customers with optional search by name.","operationId":"list","parameters":[{"name":"page","in":"query","description":"Page number (0-based)","required":false,"schema":{"type":"string","default":""}},{"name":"size","in":"query","description":"Page size","required":false,"schema":{"type":"string","default":""}},{"name":"search","in":"query","description":"Search by name (case-insensitive partial match)","required":false,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"Customers listed","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageCustomerResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageCustomerResponse"}}}}}},"post":{"tags":["Customers"],"summary":"Create a customer","description":"Creates a new customer/recipient profile for the authenticated tenant.","operationId":"create_2","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerCreateRequest"}}},"required":true},"responses":{"201":{"description":"Customer created","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"400":{"description":"Validation error","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}}}}}},"/api/v1/billing/stripe/webhook":{"post":{"tags":["Billing"],"summary":"Stripe webhook endpoint","description":"Receives Stripe payment events. Verifies HMAC signature, then dispatches to handler. Handles: checkout.session.completed, customer.subscription.deleted, customer.subscription.updated, invoice.payment_succeeded, invoice.payment_failed.","operationId":"handleStripeWebhook","parameters":[{"name":"Stripe-Signature","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"string"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/billing/portal":{"post":{"tags":["Billing"],"summary":"Create a Stripe Customer Portal session","description":"Returns a short-lived URL to the Stripe-hosted billing self-service portal where the tenant can update payment methods, view invoices, and manage their subscription. 503 if Stripe not configured ; 400 if tenant has no Stripe customer linked yet.","operationId":"createPortalSession","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/billing/checkout":{"post":{"tags":["Billing"],"summary":"Create a Stripe Checkout Session for plan upgrade","description":"Body: { plan: 'pro'|'business', interval: 'monthly'|'annual' }. Returns { url } for client redirect. 503 if Stripe not configured.","operationId":"createCheckoutSession","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/billing/cancel":{"post":{"tags":["Billing"],"summary":"Cancel the current tenant's subscription","description":"EU-compliant in-app cancellation. Sets cancel_at_period_end on Stripe if configured; always records an audit event so admin can follow up.","operationId":"cancelSubscription","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/auth/otp/verify":{"post":{"tags":["Authentication"],"summary":"Verify OTP and login","description":"Verifies the OTP code and returns a fresh API key for the user. The API key is regenerated on each successful login — the previous key becomes invalid. This is a public endpoint — no API key required.","operationId":"verifyOtp_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpVerifyBody"}}},"required":true},"responses":{"200":{"description":"OTP verified, API key returned","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Invalid or expired OTP","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"404":{"description":"Email not found","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid request","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/auth/otp/request":{"post":{"tags":["Authentication"],"summary":"Request OTP code","description":"Sends a 6-digit OTP code to the user's email. The code is valid for 10 minutes. This is a public endpoint — no API key required.","operationId":"requestOtp_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OtpRequestBody"}}},"required":true},"responses":{"200":{"description":"OTP sent successfully","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"404":{"description":"Email not found","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid request","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/auth/google":{"post":{"tags":["Authentication"],"summary":"Google OAuth login","description":"Exchanges a Google authorization code for a Doxnex API key. If the email is already registered, returns the existing tenant's key (after rotating it for security). If the email is new, auto-creates a DEMO account and returns the fresh key. This is a public endpoint — no Doxnex API key required.","operationId":"googleLogin","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleAuthBody"}}},"required":true},"responses":{"200":{"description":"Authenticated — API key returned","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid or missing authorization code","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Google rejected the code or email not verified","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"503":{"description":"Google OAuth not configured on this server","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/articles":{"get":{"tags":["Articles"],"summary":"List articles for current tenant","operationId":"list_1","parameters":[{"name":"search","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Article"}}}}}}},"post":{"tags":["Articles"],"summary":"Create a new article","operationId":"create_3","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Article"}}}}}}},"/api/v1/api-keys":{"get":{"tags":["API Keys"],"summary":"List all API keys for current tenant","operationId":"findAll_2","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyResponse"}}}}}}},"post":{"tags":["API Keys"],"summary":"Create a new API key","description":"Creates a new API key. The raw key is shown ONLY ONCE in the response.","operationId":"create_4","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreateRequest"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiKeyCreatedResponse"}}}}}}},"/api/v1/admin/groups/{groupId}/bulk-import-tenants":{"post":{"tags":["Multi-Filiales Admin (Bulk)"],"summary":"Bulk import tenants into a group via CSV upload","description":"Required CSV columns: tenant_id, code, name. Optional: attach_to_group. All-or-nothing: any validation error rolls back the entire import.","operationId":"bulkImportTenants","parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}},"required":["file"]}}}},"responses":{"200":{"description":"Import succeeded — returns row count + duration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}},"400":{"description":"CSV invalid or row validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}},"403":{"description":"Caller is not the group owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}},"404":{"description":"Group not found or archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}},"413":{"description":"CSV exceeds size limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkImportResult"}}}}}}},"/api/v1/admin/cert-watcher/trigger":{"post":{"tags":["Admin · Cert Expiry Watcher"],"summary":"Trigger the cert expiry scan synchronously","description":"Runs CertExpiryWatcher.runOnce() and returns the number of wallets processed. The scheduled job runs at 08:00 UTC every day; this endpoint is for debug, smoke tests, and the STUDI demo.","operationId":"trigger","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/account/secondary-country":{"post":{"tags":["Account"],"summary":"Set the Essential plan secondary country","description":"Body: { country: \"DE\" }. Reserved to ESSENTIAL plan. Limit: 1 change per 30 days.","operationId":"setSecondaryCountry","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecondaryCountryRequest"}}},"required":true},"responses":{"200":{"description":"Secondary country updated","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Invalid country, FR not allowed, or 30-day cooldown not elapsed","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"403":{"description":"Plan does not include this feature (non-ESSENTIAL)","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/account/register":{"post":{"tags":["Account"],"summary":"Register a new account","description":"Self-service registration. Creates a tenant and a DEMO API key. The raw API key is returned ONLY ONCE — save it securely.","operationId":"register","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterRequest"}}},"required":true},"responses":{"201":{"description":"Account created successfully","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RegisterResponse"}}}},"400":{"description":"Invalid request or validation error","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RegisterResponse"}}}},"409":{"description":"Email already registered","content":{"*/*":{"schema":{"$ref":"#/components/schemas/RegisterResponse"}}}}}}},"/api/v1/account/recover":{"post":{"tags":["Account"],"summary":"Recover API key","description":"Sends a recovery email with API key details to the registered email address.","operationId":"recover","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecoverRequest"}}},"required":true},"responses":{"200":{"description":"Recovery email sent","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"404":{"description":"No account found for this email","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/account/logo":{"post":{"tags":["Account"],"summary":"Upload tenant logo","description":"Upload a Base64-encoded logo image (PNG/JPEG) for use in generated documents. Max recommended size: 200KB. The logo will appear in the document header instead of the default Doxnex logo.","operationId":"uploadLogo","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"Logo uploaded successfully","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"400":{"description":"Logo too large or invalid","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/users/{userId}/role":{"patch":{"tags":["Users"],"summary":"Change a user's role (OWNER only)","operationId":"changeRole","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/tenant/tunisia/settings":{"get":{"tags":["Tenant Tunisia"],"summary":"Current tenant TTN settings","operationId":"getSettings_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TenantTunisiaSettingsDto"}}}}}},"patch":{"tags":["Tenant Tunisia"],"summary":"Partial update of TTN settings","operationId":"updateSettings","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantTunisiaSettingsPatchDto"}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TenantTunisiaSettingsDto"}}}}}}},"/api/v1/received-invoices/{id}/status":{"patch":{"tags":["Received Invoices"],"summary":"Update the status of a received invoice","description":"Allowed values: received, validated, accepted, rejected, paid.","operationId":"updateStatus","parameters":[{"name":"id","in":"path","description":"Received invoice id","required":true,"schema":{"type":"string","default":""}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/documents/{id}/status":{"patch":{"tags":["Documents"],"summary":"Update document status","operationId":"updateStatus_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/documents/{id}/quote-status":{"patch":{"tags":["Documents"],"summary":"Update quote status","operationId":"updateQuoteStatus","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}},"required":true},"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/health":{"get":{"tags":["Health"],"summary":"Health check","operationId":"health","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/webhooks/{id}":{"get":{"tags":["Webhooks"],"summary":"Get a webhook endpoint by ID","operationId":"findById_1","parameters":[{"name":"id","in":"path","description":"Webhook endpoint ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}}}}},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook endpoint","operationId":"delete_3","parameters":[{"name":"id","in":"path","description":"Webhook endpoint ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK"}}}},"/api/v1/users":{"get":{"tags":["Users"],"summary":"List team members (OWNER/ADMIN)","operationId":"list_2","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"type":"object","additionalProperties":{}}}}}}}}},"/api/v1/users/me":{"get":{"tags":["Users"],"summary":"Get current user profile","operationId":"me","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/tenant/tunisia/audit":{"get":{"tags":["Tenant Tunisia"],"summary":"Last N TTN audit events for the current tenant","description":"Returns the most recent tenant_ttn_audit entries (default 10, max 200) for the timeline widget in Settings > Tunisia Compliance AND the full /tn/logs page (LOT STUDI-THURSDAY chantier 2.2).","operationId":"getAuditHistory","parameters":[{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":10}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/templates/slug/{slug}":{"get":{"tags":["Templates"],"summary":"Get template by slug","description":"Looks up template by slug. Falls back to global templates if not found for tenant.","operationId":"findBySlug","parameters":[{"name":"slug","in":"path","description":"Template slug","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TemplateResponse"}}}}}}},"/api/v1/sirene/search":{"get":{"tags":["SIRENE"],"summary":"Search French companies by name or SIREN/SIRET","operationId":"search","parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/signature-wallet/ttn-email-template/test":{"get":{"tags":["Signature Wallet"],"summary":"Generate TEST environment email template for TTN","operationId":"getTestEmailTemplate","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TtnEmailTemplate"}}}}}}},"/api/v1/signature-wallet/ttn-email-template/prod":{"get":{"tags":["Signature Wallet"],"summary":"Generate PROD environment email template (requires TEST_APPROVED)","operationId":"getProdEmailTemplate","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TtnEmailTemplate"}}}}}}},"/api/v1/signature-wallet/ttn-email-template/enterprise-id":{"get":{"tags":["Signature Wallet"],"summary":"Generate Enterprise-ID SEAL activation email template","operationId":"getEnterpriseIdEmailTemplate","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/TtnEmailTemplate"}}}}}}},"/api/v1/signature-wallet/history":{"get":{"tags":["Signature Wallet"],"summary":"Get the audit log of wallet changes","operationId":"getHistory","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SignatureWalletHistory"}}}}}}}},"/api/v1/reports/vat":{"get":{"tags":["Reports"],"summary":"VAT collected report","operationId":"vat","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/reports/top-clients":{"get":{"tags":["Reports"],"summary":"Top clients by revenue","operationId":"topClients","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":10}},{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/reports/summary":{"get":{"tags":["Reports"],"summary":"Dashboard summary: totals, counts, status breakdown","operationId":"summary","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/reports/revenue":{"get":{"tags":["Reports"],"summary":"Revenue grouped by month","operationId":"revenue","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/reports/fec":{"get":{"tags":["Reports"],"summary":"FEC export (Fichier des Ecritures Comptables)","description":"French standard accounting export, pipe-separated. Required by DGFiP (Art. A. 47 A-1 LPF).","operationId":"exportFec","parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string"}},{"name":"to","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}}},"/api/v1/reports/dso":{"get":{"tags":["Reports"],"summary":"Days Sales Outstanding (average payment delay)","operationId":"dso","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/reconciliation/transactions":{"get":{"tags":["Reconciliation"],"summary":"List bank transactions for the caller's tenant","operationId":"listTransactions","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageBankTransaction"}}}}}}},"/api/v1/reconciliation/matches":{"get":{"tags":["Reconciliation"],"summary":"List reconciliation matches for the caller's tenant","operationId":"listMatches","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["PENDING","VALIDATED","REJECTED"]}},{"name":"category","in":"query","required":false,"schema":{"type":"string","enum":["HIGH","MEDIUM","LOW"]}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageReconciliationMatch"}}}}}}},"/api/v1/received-invoices":{"get":{"tags":["Received Invoices"],"summary":"List received invoices for current tenant","description":"Returns a paginated list ordered by received_at DESC.","operationId":"list_3","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/received-invoices/{id}":{"get":{"tags":["Received Invoices"],"summary":"Get a received invoice by id","operationId":"getById_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/received-invoices/{id}/xml":{"get":{"tags":["Received Invoices"],"summary":"Download the original CII/UBL XML of a received invoice","operationId":"downloadXml","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}}},"/api/v1/public/validate/status":{"get":{"tags":["Public Validator"],"summary":"Check validation rate limit status","description":"Returns remaining validation and AI fix quota for the caller's IP.","operationId":"status","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/public/invitation/{token}":{"get":{"tags":["Public Invitation"],"summary":"Look up an invitation by token (read-only welcome screen)","operationId":"lookup","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Forwarded-For","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/public/ai-demo/examples":{"get":{"tags":["public-ai-demo-controller"],"operationId":"getExamples","parameters":[{"name":"juridiction","in":"query","required":false,"schema":{"type":"string","default":"FR"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/mfa/status":{"get":{"tags":["Multi-Factor Authentication"],"summary":"MFA status for the authenticated user","operationId":"status_1","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/mfa/devices":{"get":{"tags":["Multi-Factor Authentication"],"summary":"List active trusted devices","description":"Sprint 2.6-bis : returns the list of devices where the user has chosen to skip MFA verification for 30 days. Each device shows label, IP, created/last-used dates and expiry.","operationId":"listDevices","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/invitations/preview":{"get":{"tags":["Group Invitations"],"summary":"Preview an invitation by raw token (PUBLIC, no auth)","description":"The raw token from the magic link email is the capability. Returns minimum info needed to decide whether to accept.","operationId":"previewInvitation","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","minLength":1}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/InvitationPreviewResponse"}}}}}}},"/api/v1/info":{"get":{"tags":["Health"],"summary":"Service information","description":"Returns service name, version, and uptime. No authentication required.","operationId":"info","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/groups/{id}":{"get":{"tags":["Tenant Groups"],"summary":"Get a single group by id","operationId":"getGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Group found","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"403":{"description":"Caller is not a member","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}},"404":{"description":"Group archived or missing","content":{"*/*":{"schema":{"$ref":"#/components/schemas/GroupResponse"}}}}}},"delete":{"tags":["Tenant Groups"],"summary":"Archive a group (soft-delete)","description":"Only the current owner can archive. Tenants survive with tenant_group_id = NULL.","operationId":"archiveGroup","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}}},"/api/v1/groups/{id}/top-tenants":{"get":{"tags":["Group Aggregations"],"summary":"Top-N tenants by revenue inside a single currency","description":"Currency is required: cross-currency ranking is undefined.","operationId":"getTopTenants","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"currency","in":"query","description":"ISO currency code (EUR, TND, OMR, USD, GBP...)","required":true,"schema":{"type":"string","default":"","pattern":"[A-Z]{3,10}"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":10,"maximum":50,"minimum":1}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TenantStatsResponse"}}}}}}}},"/api/v1/groups/{id}/tenants":{"get":{"tags":["Tenant Groups"],"summary":"List tenants attached to the group (cursor-paginated)","description":"Sprint 2.3 — keyset pagination (createdAt DESC + id DESC). Caller must be a member (any role). Supports `cursor` and `limit` (max 100). Critical for distributors with N>50 subsidiaries.","operationId":"listTenants","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","format":"int32","maximum":100,"minimum":1}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PagedResponseTenantSummary"}}}}}}},"/api/v1/groups/{id}/aggregation":{"get":{"tags":["Group Aggregations"],"summary":"Get per-currency aggregated totals for a group","operationId":"getAggregation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AggregationResponse"}}}}}}},"/api/v1/gdpr/export":{"get":{"tags":["GDPR"],"summary":"Export tenant data","description":"Exports all data for the current tenant (GDPR Article 20 — Right to data portability)","operationId":"exportData","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/documents":{"get":{"tags":["Documents"],"summary":"List documents for current tenant","operationId":"list_4","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}},{"name":"type","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"active"}},{"name":"dateFrom","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"dateTo","in":"query","required":false,"schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageDocumentMetadata"}}}}}}},"/api/v1/documents/{id}":{"get":{"tags":["Documents"],"summary":"Get document metadata","operationId":"getById_2","parameters":[{"name":"id","in":"path","description":"Document ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/DocumentMetadata"}}}}}},"delete":{"tags":["Documents"],"summary":"Soft-delete a document","operationId":"delete_4","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}},"/api/v1/documents/{id}/xml":{"get":{"tags":["Documents"],"summary":"Download standalone XML (UBL/CII)","operationId":"downloadXml_1","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}}},"/api/v1/documents/{id}/whatsapp-link":{"get":{"tags":["Documents"],"summary":"Generate WhatsApp sharing link for a document","operationId":"whatsappLink","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"phone","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/documents/{id}/url":{"get":{"tags":["Documents"],"summary":"Get presigned download URL","operationId":"getDownloadUrl","parameters":[{"name":"id","in":"path","description":"Document ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{"type":"string"}}}}}}}},"/api/v1/documents/{id}/submission":{"get":{"tags":["Documents"],"summary":"Get submission status","operationId":"getSubmissionStatus","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/documents/{id}/secondary-xml":{"get":{"tags":["Documents"],"summary":"Download secondary compliance XML","operationId":"downloadSecondaryXml","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}}},"/api/v1/documents/{id}/secondary-pdf":{"get":{"tags":["Documents"],"summary":"Download secondary compliance PDF (Factur-X PDF/A-3 with embedded CII)","description":"Available only when the secondary format is factur-x*. For Peppol/TEIF secondaries use /secondary-xml instead.","operationId":"downloadSecondaryPdf","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}}},"/api/v1/documents/{id}/download":{"get":{"tags":["Documents"],"summary":"Download document PDF","operationId":"download","parameters":[{"name":"id","in":"path","description":"Document ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}}},"/api/v1/documents/{id}/amendment-chain":{"get":{"tags":["Document Amendments"],"summary":"List the full amendment chain of a document","description":"Given any document in the chain (original or amendment), walks up to the root original then returns the whole chain ordered by amendment_number ascending.","operationId":"chain","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DocumentMetadata"}}}}}}}},"/api/v1/documents/public/{viewId}":{"get":{"tags":["Public Documents"],"summary":"Public document page","description":"Returns an HTML page showing document info and a download button. No API key required.","operationId":"viewDocument","parameters":[{"name":"viewId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string"}}}}}}},"/api/v1/documents/public/{viewId}/download":{"get":{"tags":["Public Documents"],"summary":"Public document download","description":"Downloads the PDF document. No API key required.","operationId":"downloadDocument","parameters":[{"name":"viewId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}}},"/api/v1/documents/export":{"get":{"tags":["Documents"],"summary":"Export documents as CSV","operationId":"exportDocuments","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"csv"}},{"name":"type","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"}},{"name":"dateFrom","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"dateTo","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"locale","in":"query","required":false,"schema":{"type":"string","default":"en"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"string","format":"byte"}}}}}}},"/api/v1/dashboard/kpis":{"get":{"tags":["Dashboard"],"summary":"Top-row KPIs for the dashboard","description":"Returns 4 metrics: compliance rate, average DSO, top client of the month, and country coverage (used / allowed). Tenant-scoped via API key.","operationId":"getKpis","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/customers/defaults":{"get":{"tags":["Customers"],"summary":"Get default preferences for a country","description":"Returns suggested language, currency and compliance format based on ISO country code.","operationId":"defaults","parameters":[{"name":"country","in":"query","description":"ISO country code (e.g. FR, OM, TN)","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/Defaults"}}}}}}},"/api/v1/compliance/formats":{"get":{"tags":["Compliance matrix"],"summary":"List all known compliance formats","description":"Returns all ComplianceFormat enum values with family and standard.","operationId":"listAllFormats","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/FormatDto"}}}}}}}},"/api/v1/compliance/countries":{"get":{"tags":["Compliance matrix"],"summary":"List all supported countries","description":"Returns ISO code, display name and currency for each supported country.","operationId":"listSupportedCountries","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CountryDto"}}}}}}}},"/api/v1/compliance/countries/{iso}/metadata":{"get":{"tags":["Compliance matrix"],"summary":"Portal metadata for a given country","description":"Returns tax rates, tax-id labels, language hints and region grouping for the country. Drives the portal's regional UI. Returns 404 if the country is supported by the format matrix but has no metadata table entry yet (frontend should degrade gracefully).","operationId":"getCountryMetadata","parameters":[{"name":"iso","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CountryMetadataDto"}}}}}}},"/api/v1/compliance/countries/{iso}/formats":{"get":{"tags":["Compliance matrix"],"summary":"Primary + compatible secondaries for a given country","description":"Returns the country's fiscal primary format and the list of formats that are valid secondaries when it is the buyer.","operationId":"getCountryFormats","parameters":[{"name":"iso","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/CountryFormatsDto"}}}}}}},"/api/v1/billing/plans":{"get":{"tags":["Billing"],"summary":"Public plan catalog","description":"Returns the list of publicly-listed plans with prices and limits. Skips placeholder rows (Stripe IDs not yet configured).","operationId":"listPublicPlans","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"array","items":{"type":"object","additionalProperties":{}}}}}}}}},"/api/v1/archive/verify":{"get":{"tags":["Archive"],"summary":"Verify archive chain integrity","description":"Checks that the SHA-256 hash chain is intact for all archived documents.","operationId":"verifyIntegrity","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/archive/history":{"get":{"tags":["Archive"],"summary":"Get archive history","description":"Returns paginated archive history with hash chain details.","operationId":"getHistory_1","parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":20}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageDocumentArchive"}}}}}}},"/api/v1/api-keys/{id}":{"get":{"tags":["API Keys"],"summary":"Get an API key by ID","operationId":"findById_2","parameters":[{"name":"id","in":"path","description":"API key ID","required":true,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiKeyResponse"}}}}}}},"/api/v1/admin/plans":{"get":{"tags":["Admin"],"summary":"List available API plans","description":"Returns all available Doxnex plans with their limits and descriptions.","operationId":"listPlans","responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/admin/dashboard":{"get":{"tags":["Admin"],"summary":"Dashboard KPIs","description":"Returns comprehensive metrics: total docs, today count, type breakdown, template count, active API keys, current plan.","operationId":"dashboard","responses":{"200":{"description":"Dashboard KPIs returned","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/admin/audit":{"get":{"tags":["Admin"],"summary":"View audit trail","description":"Returns paginated audit events for the current tenant.","operationId":"auditTrail","parameters":[{"name":"page","in":"query","description":"Page number (0-based)","required":false,"schema":{"type":"string","default":""}},{"name":"size","in":"query","description":"Page size","required":false,"schema":{"type":"string","default":""}}],"responses":{"200":{"description":"Audit events returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageAuditEvent"}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageAuditEvent"}}}}}}},"/api/v1/admin/audit-events":{"get":{"tags":["Admin · Audit Events"],"summary":"List audit events for the caller's tenant","description":"Returns paginated audit events filtered by the caller's tenant. Cross-tenant access is structurally impossible — the query keys on a server-side computed tenant_id_hash. Requires OWNER or ADMIN role.","operationId":"list_5","parameters":[{"name":"eventType","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"uniqueItems":true}},{"name":"fromDate","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"toDate","in":"query","required":false,"schema":{"type":"string","format":"date-time"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":0}},{"name":"size","in":"query","required":false,"schema":{"type":"integer","format":"int32","default":50}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"$ref":"#/components/schemas/PageSecurityAuditEventDto"}}}}}}},"/api/v1/account/usage":{"get":{"tags":["Account"],"summary":"Get API usage statistics","description":"Returns detailed usage stats: daily/monthly counters, document counts by type, today's count.","operationId":"usage","responses":{"200":{"description":"Usage stats returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"$ref":"#/components/schemas/UsageResponse"}}}}}}},"/api/v1/account/settings/region":{"get":{"tags":["Account"],"summary":"Get regional configuration","description":"Returns the multi-region configuration derived from the tenant's country: region (EU/GCC/AFRICA), default compliance format, currency, tax rates and feature flags.","operationId":"getRegionSettings","responses":{"200":{"description":"Region settings returned","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}},"/api/v1/account/info":{"get":{"tags":["Account"],"summary":"Get account information","description":"Returns tenant details, current plan, and usage summary for the authenticated API key.","operationId":"info_1","responses":{"200":{"description":"Account info returned","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AccountInfoResponse"}}}},"401":{"description":"Missing or invalid API key","content":{"*/*":{"schema":{"$ref":"#/components/schemas/AccountInfoResponse"}}}}}}},"/api/v1/users/{userId}":{"delete":{"tags":["Users"],"summary":"Remove a user (OWNER/ADMIN)","operationId":"remove","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}}},"/api/v1/mfa/devices/{deviceId}":{"delete":{"tags":["Multi-Factor Authentication"],"summary":"Revoke a specific trusted device","description":"Sprint 2.6-bis : revokes a single trusted device. Cross-user revoke attempts return 403 Forbidden + audit log entry.","operationId":"revokeDevice","parameters":[{"name":"deviceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object"}}}}}}},"/api/v1/invitations/{id}":{"delete":{"tags":["Group Invitations"],"summary":"Revoke a pending invitation","description":"Inviter or current group owner can revoke.","operationId":"revokeInvitation","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"No Content"}}}},"/api/v1/gdpr/erasure/{tenantId}":{"delete":{"tags":["GDPR"],"summary":"Request data erasure","description":"Requests complete erasure of tenant data (GDPR Article 17 — Right to erasure)","operationId":"requestErasure","parameters":[{"name":"tenantId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"*/*":{"schema":{"type":"object","additionalProperties":{}}}}}}}}},"components":{"schemas":{"TemplateUpdateRequest":{"type":"object","default":null,"description":"Request to update a template (partial update)","properties":{"name":{"type":"string","default":"","description":"Human-readable name"},"description":{"type":"string","default":"","description":"Template description"},"htmlContent":{"type":"string","default":"","description":"Updated Thymeleaf HTML content"},"cssContent":{"type":"string","default":"","description":"Updated CSS content"},"locale":{"type":"string","default":"","description":"Locale override"},"active":{"type":"boolean","default":false,"description":"Set to false to deactivate template"}}},"TemplateResponse":{"type":"object","default":null,"description":"Document template details","properties":{"id":{"type":"string","default":"","description":"Unique identifier"},"slug":{"type":"string","default":"","description":"URL-friendly slug","example":"receipt-premium"},"name":{"type":"string","default":"","description":"Human-readable name","example":"Premium Receipt"},"description":{"type":"string","default":"","description":"Template description"},"documentType":{"type":"string","default":"","description":"Document type: receipt, invoice, delivery"},"htmlContent":{"type":"string","default":"","description":"Thymeleaf HTML content"},"cssContent":{"type":"string","default":"","description":"CSS content"},"version":{"type":"integer","format":"int32","default":"","description":"Template version number"},"active":{"type":"boolean","default":false,"description":"Whether template is active"},"locale":{"type":"string","default":"","description":"Locale"},"createdAt":{"type":"string","format":"date-time","default":"","description":"Creation timestamp"},"updatedAt":{"type":"string","format":"date-time","default":"","description":"Last update timestamp"}}},"SignatureWalletDto":{"type":"object","properties":{"tenantId":{"type":"string"},"method":{"type":"string","enum":["DIGIGO","ENTERPRISE_ID_SEAL","ID_TRUST_USB","NONE"]},"claimedRole":{"type":"string"},"certificateCn":{"type":"string"},"certificateSerial":{"type":"string"},"certificateExpiresAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["PENDING","PENDING_TTN_APPROVAL","ACTIVE","EXPIRED","REVOKED","SUSPENDED"]},"ttnTestUsername":{"type":"string"},"ttnProdUsername":{"type":"string"},"ttnEnvironment":{"type":"string","enum":["TEST","PROD"]},"ttnSubmissionStatus":{"type":"string","enum":["NOT_SUBMITTED","EMAIL_TEMPLATE_GENERATED","SUBMITTED_WAITING_TEST","TEST_APPROVED","SUBMITTED_WAITING_PROD","PROD_APPROVED","REJECTED"]},"ttnSubmissionDateTest":{"type":"string","format":"date-time"},"ttnApprovalDateTest":{"type":"string","format":"date-time"},"ttnSubmissionDateProd":{"type":"string","format":"date-time"},"ttnApprovalDateProd":{"type":"string","format":"date-time"},"ttnRejectionReason":{"type":"string"},"ttnTestMatricule":{"type":"string"},"ttnProdMatricule":{"type":"string"},"enterpriseIdSealKeyConfigured":{"type":"boolean"},"enterpriseIdEmailSentAt":{"type":"string","format":"date-time"},"enterpriseIdEmailTo":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"activatedAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":"string","format":"date-time"}}},"CustomerUpdateRequest":{"type":"object","default":null,"description":"Update an existing customer profile (partial update, only provided fields change)","properties":{"code":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"contactName":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"},"vatNumber":{"type":"string"},"siret":{"type":"string"},"notes":{"type":"string"},"preferredLanguage":{"type":"string"},"preferredCurrency":{"type":"string"},"preferredCompliance":{"type":"string"}}},"CustomerResponse":{"type":"object","default":null,"description":"Customer/recipient profile","properties":{"id":{"type":"string","default":"","description":"Customer UUID"},"code":{"type":"string","default":"","description":"Internal code"},"name":{"type":"string","default":"","description":"Company/customer name"},"email":{"type":"string","default":"","description":"Email"},"phone":{"type":"string","default":"","description":"Phone"},"contactName":{"type":"string","default":"","description":"Contact person"},"address":{"type":"string","default":"","description":"Street address"},"city":{"type":"string","default":"","description":"City"},"postalCode":{"type":"string","default":"","description":"Postal code"},"country":{"type":"string","default":"","description":"Country ISO code"},"vatNumber":{"type":"string","default":"","description":"VAT number"},"siret":{"type":"string","default":"","description":"SIRET number"},"notes":{"type":"string","default":"","description":"Internal notes"},"preferredLanguage":{"type":"string","default":"","description":"Preferred language"},"preferredCurrency":{"type":"string","default":"","description":"Preferred currency"},"preferredCompliance":{"type":"string","default":"","description":"Preferred compliance format"},"createdAt":{"type":"string","format":"date-time","default":"","description":"Created timestamp"},"updatedAt":{"type":"string","format":"date-time","default":"","description":"Last updated timestamp"}}},"Article":{"type":"object","properties":{"id":{"type":"string"},"tenantId":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"reference":{"type":"string"},"unitPriceExcl":{"type":"number"},"vatRate":{"type":"number"},"unit":{"type":"string"},"category":{"type":"string"},"active":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"WebhookCreateRequest":{"type":"object","default":null,"description":"Request to create a new webhook endpoint","properties":{"url":{"type":"string","default":"","description":"URL to receive webhook POST requests","example":"https://yourapp.com/webhooks/doxnex","minLength":1},"events":{"type":"array","default":"","description":"Event types to subscribe to. Use '*' for all events.","example":["document.generated","document.delivered"],"items":{"type":"string"},"minItems":1}},"required":["events","url"]},"WebhookResponse":{"type":"object","default":null,"description":"Webhook endpoint configuration and status","properties":{"id":{"type":"string","default":"","description":"Unique identifier"},"url":{"type":"string","default":"","description":"Target URL"},"events":{"type":"array","default":"","description":"Subscribed event types","items":{"type":"string"}},"active":{"type":"boolean","default":false,"description":"Whether this endpoint is active"},"failureCount":{"type":"integer","format":"int32","default":"","description":"Consecutive delivery failure count"},"lastTriggeredAt":{"type":"string","format":"date-time","default":"","description":"Last event delivery timestamp"},"lastStatusCode":{"type":"integer","format":"int32","default":"","description":"Last HTTP status code from delivery attempt"},"createdAt":{"type":"string","format":"date-time","default":"","description":"Creation timestamp"}}},"SchematronSuggestionRequest":{"type":"object","properties":{"juridiction":{"type":"string","minLength":1},"schematronCode":{"type":"string","minLength":1},"schematronDescription":{"type":"string"},"xmlExcerpt":{"type":"string","minLength":1}},"required":["juridiction","schematronCode","xmlExcerpt"]},"CancelTransferRequest":{"type":"object","properties":{"reason":{"type":"string","maxLength":500,"minLength":0}}},"TransferResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"groupId":{"type":"string","format":"uuid"},"fromUserId":{"type":"string"},"toUserId":{"type":"string"},"status":{"type":"string","enum":["INITIATED","ACCEPTED","COMPLETED","CANCELLED","REJECTED","EXPIRED"]},"initiatedAt":{"type":"string","format":"date-time"},"acceptedAt":{"type":"string","format":"date-time"},"holdUntil":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time"},"cancelledAt":{"type":"string","format":"date-time"},"cancelledByUserId":{"type":"string"},"cancellationReason":{"type":"string"}}},"TemplateCreateRequest":{"type":"object","default":null,"description":"Request to create a new document template","properties":{"slug":{"type":"string","default":"","description":"URL-friendly unique identifier","example":"receipt-premium","minLength":1,"pattern":"^[a-z0-9-]+$"},"name":{"type":"string","default":"","description":"Human-readable name","example":"Premium Receipt","minLength":1},"description":{"type":"string","default":"","description":"Template description","example":"Premium branded receipt template with QR code"},"documentType":{"type":"string","default":"","description":"Document type: receipt, invoice, delivery","example":"receipt","minLength":1},"htmlContent":{"type":"string","default":"","description":"Thymeleaf HTML template content","minLength":1},"cssContent":{"type":"string","default":"","description":"Optional CSS content (injected into template)"},"locale":{"type":"string","default":"","description":"Locale (default: fr-FR)","example":"fr-FR"}},"required":["documentType","htmlContent","name","slug"]},"ImportResult":{"type":"object","properties":{"batchId":{"type":"string","format":"uuid"},"format":{"type":"string","enum":["OFX","QIF","CSV_AUTO","UNKNOWN"]},"profile":{"type":"string","enum":["SHINE_FR","SHINE_TN","BANK_MUSCAT","GENERIC"]},"transactionCount":{"type":"integer","format":"int32"},"warnings":{"type":"array","items":{"type":"string"}}}},"ReconciliationMatch":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenantId":{"type":"string"},"documentId":{"type":"string"},"bankTransactionId":{"type":"string","format":"uuid"},"score":{"type":"number"},"scoreCategory":{"type":"string","enum":["HIGH","MEDIUM","LOW"]},"matchingLayer":{"type":"string","enum":["STRICT","FUZZY","AGGREGATED"]},"status":{"type":"string","enum":["PENDING","VALIDATED","REJECTED"]},"validatedBy":{"type":"string"},"validatedAt":{"type":"string","format":"date-time"},"rejectionReason":{"type":"string"},"metadata":{"type":"object","additionalProperties":{}},"createdAt":{"type":"string","format":"date-time"}}},"SignRequest":{"type":"object","properties":{"signerName":{"type":"string"},"signerEmail":{"type":"string"}}},"ContactRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":200,"minLength":0},"company":{"type":"string","maxLength":200,"minLength":0},"email":{"type":"string","format":"email","maxLength":200,"minLength":0},"phone":{"type":"string","maxLength":50,"minLength":0},"employees":{"type":"string","maxLength":50,"minLength":0},"message":{"type":"string","maxLength":5000,"minLength":0}},"required":["company","email","name"]},"AiFixRequest":{"type":"object","default":null,"description":"Request for AI-powered validation error fix","properties":{"code":{"type":"string","default":"","description":"Check code, e.g. BR-S-05","minLength":1},"rule":{"type":"string","default":"","description":"Rule description"},"message":{"type":"string","default":"","description":"Error message"},"xpath":{"type":"string","default":"","description":"XPath of the faulty element"},"currentValue":{"type":"string","default":"","description":"Current value found"},"expectedValue":{"type":"string","default":"","description":"Expected value"},"xmlContext":{"type":"string","default":"","description":"XML context (~20 lines around the error)"},"language":{"type":"string","default":"","description":"Response language: fr, en, ar, de, es, it, pt, tr"}},"required":["code"]},"PublicDemoRequest":{"type":"object","properties":{"juridiction":{"type":"string","minLength":1},"schematronCode":{"type":"string","minLength":1},"schematronDescription":{"type":"string"},"xmlExcerpt":{"type":"string","maxLength":5000,"minLength":0}},"required":["juridiction","schematronCode","xmlExcerpt"]},"MfaVerifyRequest":{"type":"object","properties":{"code":{"type":"string","maxLength":6,"minLength":6,"pattern":"\\d{6}"},"trustDevice":{"type":"boolean"}},"required":["code"]},"RecoveryCodeRequest":{"type":"object","properties":{"recoveryCode":{"type":"string","maxLength":14,"minLength":12}},"required":["recoveryCode"]},"MfaCodeRequest":{"type":"object","properties":{"code":{"type":"string","maxLength":6,"minLength":6,"pattern":"\\d{6}"}},"required":["code"]},"AcceptInvitationRequest":{"type":"object","properties":{"token":{"type":"string","maxLength":200,"minLength":20}},"required":["token"]},"MembershipResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string"},"groupId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["GROUP_OWNER","GROUP_ADMIN","GROUP_VIEWER"]},"invitedAt":{"type":"string","format":"date-time"},"acceptedAt":{"type":"string","format":"date-time"},"revokedAt":{"type":"string","format":"date-time"}}},"CreateGroupRequest":{"type":"object","properties":{"name":{"type":"string","maxLength":255,"minLength":0},"type":{"type":"string","enum":["STANDARD","ACCOUNTANT","FRANCHISE","HOLDING"]},"description":{"type":"string","maxLength":1000,"minLength":0}},"required":["name"]},"GroupResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["STANDARD","ACCOUNTANT","FRANCHISE","HOLDING"]},"description":{"type":"string"},"primaryTenantId":{"type":"string"},"ownerUserId":{"type":"string"},"tenantCount":{"type":"integer","format":"int64"},"memberCount":{"type":"integer","format":"int64"},"brandingInherits":{"type":"boolean"},"brandingLogoUrl":{"type":"string"},"brandingPrimaryColor":{"type":"string"},"subscriptionModel":{"type":"string","enum":["PER_TENANT","PER_GROUP"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":"string","format":"date-time"}}},"InitiateTransferRequest":{"type":"object","properties":{"toUserId":{"type":"string","maxLength":36,"minLength":0}},"required":["toUserId"]},"SendInvitationRequest":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":255,"minLength":0},"name":{"type":"string","maxLength":255,"minLength":0},"role":{"type":"string","enum":["GROUP_ADMIN","GROUP_VIEWER"]}},"required":["email","role"]},"InvitationResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"groupId":{"type":"string","format":"uuid"},"invitedEmail":{"type":"string"},"invitedName":{"type":"string"},"role":{"type":"string","enum":["GROUP_ADMIN","GROUP_VIEWER"]},"status":{"type":"string","enum":["PENDING","ACCEPTED","REJECTED","EXPIRED","REVOKED"]},"invitedByUserId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"acceptedAt":{"type":"string","format":"date-time"},"rejectedAt":{"type":"string","format":"date-time"},"revokedAt":{"type":"string","format":"date-time"}}},"GenerateDocumentResponse":{"type":"object","default":null,"description":"Document generation result with download URL and integrity hash","properties":{"documentId":{"type":"string","default":"","description":"Document unique identifier"},"type":{"type":"string","default":"","description":"Document type","example":"receipt"},"downloadUrl":{"type":"string","default":"","description":"Presigned download URL (valid for 1 hour)"},"documentHash":{"type":"string","default":"","description":"SHA-256 hash of the generated PDF (NF525 compliance)"},"documentNumber":{"type":"string","default":"","description":"Legal document number (e.g. FAC-2026-000001)"},"filename":{"type":"string","default":"","description":"Suggested filename for download (e.g. Facture_FR_FAC-2026-000011_TechVision-SAS.pdf)"},"compliance":{"type":"string","default":"","description":"Compliance mode applied: null, 'factur-x-basic', 'factur-x-en16931'"},"sequenceNumber":{"type":"integer","format":"int64","default":"","description":"Sequence number in the hash chain"},"sizeBytes":{"type":"integer","format":"int64","default":"","description":"Document size in bytes"},"createdAt":{"type":"string","format":"date-time","default":"","description":"Generation timestamp"},"publicUrl":{"type":"string","default":"","description":"Public shareable URL (no API key required)"}}},"SendEmailRequest":{"type":"object","default":null,"description":"Request to send a document by email with the PDF attached","properties":{"recipientEmail":{"type":"string","format":"email","default":"","description":"Recipient email address","example":"client@example.com","minLength":1},"recipientName":{"type":"string","default":"","description":"Recipient display name","example":"Jean Dupont"},"senderEmail":{"type":"string","default":"","description":"Sender email (defaults to noreply@doxnex.io)","example":"billing@mycompany.com"},"subject":{"type":"string","default":"","description":"Custom email subject (auto-generated if not provided)"},"message":{"type":"string","default":"","description":"Custom HTML message body"}},"required":["recipientEmail"]},"AmendmentRequestDto":{"type":"object","properties":{"reason":{"type":"string","maxLength":512,"minLength":20}},"required":["reason"]},"DocumentMetadata":{"type":"object","properties":{"id":{"type":"string"},"tenantId":{"type":"string"},"documentType":{"type":"string"},"templateId":{"type":"string"},"storageKey":{"type":"string"},"storageBucket":{"type":"string"},"sizeBytes":{"type":"integer","format":"int64"},"mimeType":{"type":"string"},"documentHash":{"type":"string"},"previousHash":{"type":"string"},"sequenceNumber":{"type":"integer","format":"int64"},"locale":{"type":"string"},"documentNumber":{"type":"string"},"customerId":{"type":"string"},"filename":{"type":"string"},"compliance":{"type":"string"},"issuerName":{"type":"string"},"recipientName":{"type":"string"},"currency":{"type":"string"},"totalExcl":{"type":"number"},"totalVat":{"type":"number"},"totalIncl":{"type":"number"},"documentTypeCode":{"type":"string"},"viewId":{"type":"string"},"payload":{"type":"object","additionalProperties":{}},"tags":{"type":"object","additionalProperties":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time"},"originalDocumentId":{"type":"string"},"legacyNoOriginalRef":{"type":"boolean"},"status":{"type":"string"},"sentAt":{"type":"string","format":"date-time"},"paidAt":{"type":"string","format":"date-time"},"cancelledAt":{"type":"string","format":"date-time"},"sentToEmail":{"type":"string"},"paymentStatus":{"type":"string"},"quoteStatus":{"type":"string"},"submissionStatus":{"type":"string"},"submissionProvider":{"type":"string"},"submissionId":{"type":"string"},"submissionDate":{"type":"string","format":"date-time"},"validationDate":{"type":"string","format":"date-time"},"validationMessage":{"type":"string"},"operationCategory":{"type":"string"},"vatOnDebits":{"type":"boolean"},"deliveryAddress":{"type":"string"},"deliveryCity":{"type":"string"},"deliveryPostalCode":{"type":"string"},"deliveryCountry":{"type":"string"},"sellerSiren":{"type":"string"},"buyerSiren":{"type":"string"},"pdfHash":{"type":"string"},"xmlHash":{"type":"string"},"archivedAt":{"type":"string","format":"date-time"},"archiveStatus":{"type":"string"},"secondaryComplianceFormat":{"type":"string"},"secondaryXmlPath":{"type":"string"},"secondaryPdfPath":{"type":"string"},"withholdingCertKey":{"type":"string"},"ttnReference":{"type":"string"},"ttnStatus":{"type":"string"},"ttnQrCode":{"type":"string"},"ttnSubmissionDate":{"type":"string","format":"date-time"},"ttnRejectionReason":{"type":"string"},"signatureProvider":{"type":"string"},"teifPayloadHash":{"type":"string"},"amendmentNumber":{"type":"integer","format":"int32"},"amendedFromId":{"type":"string"},"amendmentReason":{"type":"string"},"amendmentStatus":{"type":"string"},"stampDutyAmount":{"type":"number"},"fodecAmount":{"type":"number"},"fodecRate":{"type":"number"},"withholdingTaxAmount":{"type":"number"},"withholdingTaxRate":{"type":"number"},"schemaVersion":{"type":"string"}}},"ValidateDocumentRequest":{"type":"object","default":null,"description":"Request to validate document data before generation","properties":{"template":{"type":"string","default":"","description":"Template slug","example":"receipt-premium","minLength":1},"locale":{"type":"string","default":"","description":"Locale","example":"fr-FR","minLength":1},"data":{"type":"object","additionalProperties":{},"default":"","description":"Document data to validate"}},"required":["data","locale","template"]},"ValidationCheck":{"type":"object","default":null,"description":"Individual validation check result","properties":{"code":{"type":"string","default":"","description":"Check code","example":"VAT_COHERENCE"},"severity":{"type":"string","default":"","description":"Severity: ERROR, WARNING, INFO","example":"ERROR"},"passed":{"type":"boolean","default":false,"description":"Whether the check passed"},"message":{"type":"string","default":"","description":"Human-readable message","example":"VAT rate 20% is valid for locale fr-FR"},"field":{"type":"string","default":"","description":"Field path that failed","example":"items[2].vat_rate"},"expected":{"default":"","description":"Expected value"},"actual":{"default":"","description":"Actual value found"}}},"ValidationResult":{"type":"object","default":null,"description":"Document validation result","properties":{"valid":{"type":"boolean","default":false,"description":"Whether validation passed (no ERROR-level failures)"},"checksRun":{"type":"integer","format":"int32","default":"","description":"Number of checks executed"},"checksPassed":{"type":"integer","format":"int32","default":"","description":"Number of checks that passed"},"checksFailed":{"type":"integer","format":"int32","default":"","description":"Number of checks that failed"},"validationTimeMs":{"type":"integer","format":"int64","default":"","description":"Validation time in milliseconds"},"checks":{"type":"array","default":"","description":"Individual check results","items":{"$ref":"#/components/schemas/ValidationCheck"}}}},"GenerateDocumentRequest":{"type":"object","default":null,"description":"Request to generate a document (receipt, invoice, credit note, debit note, delivery certificate)","properties":{"template":{"type":"string","default":"","description":"Template slug to use for generation","example":"invoice-premium","minLength":1},"type":{"type":"string","default":"","description":"Document type: receipt, invoice, delivery, quote","example":"invoice","minLength":1,"pattern":"^(receipt|invoice|delivery|quote)$"},"locale":{"type":"string","default":"","description":"Document language. Arabic (ar) uses bilingual RTL templates","enum":["fr","en","de","it","es","pt","ar"],"example":"fr","pattern":"^[a-z]{2}(-[A-Z]{2})?$"},"data":{"type":"object","additionalProperties":{},"default":"","description":"Dynamic data payload for template rendering. For invoices, may include document_type_code (380/381/383/386), original_invoice_number, original_invoice_date"},"tags":{"type":"object","additionalProperties":{"type":"string"},"default":"","description":"Optional tags for document classification"},"compliance":{"type":"string","default":"","description":"E-invoicing compliance format","enum":["factur-x-basic","factur-x-en16931","factur-x-minimum","peppol-ubl","teif"],"example":"factur-x-basic"},"callbackUrl":{"type":"string","default":"","description":"Webhook URL for async delivery notification"},"customerId":{"type":"string","default":"","description":"Customer UUID — auto-populates recipient fields from saved profile"}},"required":["data","template","type"]},"CustomerCreateRequest":{"type":"object","default":null,"description":"Create a customer/recipient profile for reuse in documents","properties":{"code":{"type":"string","default":"","description":"Internal customer code (optional)","example":"CLI-001"},"name":{"type":"string","default":"","description":"Customer/company name","example":"TechVision SAS","minLength":1},"email":{"type":"string","default":"","description":"Email address","example":"comptabilite@techvision.fr"},"phone":{"type":"string","default":"","description":"Phone number","example":"+33 1 42 68 19 30"},"contactName":{"type":"string","default":"","description":"Contact person name","example":"Marie Dupont"},"address":{"type":"string","default":"","description":"Street address","example":"45 Boulevard Haussmann"},"city":{"type":"string","default":"","description":"City","example":"Paris"},"postalCode":{"type":"string","default":"","description":"Postal code","example":"75008"},"country":{"type":"string","default":"FR","description":"Country ISO code","example":"FR"},"vatNumber":{"type":"string","default":"","description":"VAT number","example":"FR 87 876543210"},"siret":{"type":"string","default":"","description":"SIRET number","example":"876 543 210 00022"},"notes":{"type":"string","default":"","description":"Internal notes"},"preferredLanguage":{"type":"string","default":"","description":"Preferred document language (e.g. fr, en, ar)","example":"fr"},"preferredCurrency":{"type":"string","default":"","description":"Preferred currency (e.g. EUR, OMR, TND)","example":"EUR"},"preferredCompliance":{"type":"string","default":"","description":"Preferred compliance format (factur-x-basic, peppol-ubl, teif)","example":"factur-x-basic"}},"required":["name"]},"OtpVerifyBody":{"type":"object","properties":{"email":{"type":"string","format":"email","minLength":1},"code":{"type":"string","minLength":1}},"required":["code","email"]},"OtpRequestBody":{"type":"object","properties":{"email":{"type":"string","format":"email","minLength":1}},"required":["email"]},"GoogleAuthBody":{"type":"object","properties":{"code":{"type":"string","minLength":1},"redirectUri":{"type":"string"}},"required":["code"]},"ApiKeyCreateRequest":{"type":"object","default":null,"description":"Request payload for creating a new API key","properties":{"name":{"type":"string","default":"","description":"Human-readable name for this API key","example":"POS Integration Key","minLength":1},"plan":{"type":"string","default":"DEMO","description":"API plan tier (DEMO, STARTER, GROWTH, SCALE). Defaults to DEMO.","example":"DEMO"}},"required":["name"]},"ApiKeyCreatedResponse":{"type":"object","default":null,"description":"Response returned when a new API key is created. The raw key is shown ONLY ONCE.","properties":{"id":{"type":"string","default":"","description":"Unique identifier of the API key"},"rawKey":{"type":"string","default":"","description":"Full raw API key value — shown ONLY ONCE at creation time","example":"dx_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"},"keyPrefix":{"type":"string","default":"","description":"Prefix for key identification (first 16 characters)","example":"dx_live_a1b2c3d4"},"name":{"type":"string","default":"","description":"Human-readable name","example":"POS Integration Key"},"plan":{"type":"string","default":"","description":"API plan tier","example":"DEMO"},"dailyLimit":{"type":"integer","format":"int32","default":"","description":"Maximum requests per day","example":100},"monthlyLimit":{"type":"integer","format":"int32","default":"","description":"Maximum requests per month","example":1000},"createdAt":{"type":"string","format":"date-time","default":"","description":"Timestamp when this key was created"}}},"BulkImportResult":{"type":"object","properties":{"groupId":{"type":"string","format":"uuid"},"totalRows":{"type":"integer","format":"int32"},"successfulImports":{"type":"integer","format":"int32"},"failedImports":{"type":"integer","format":"int32"},"errors":{"type":"array","items":{"$ref":"#/components/schemas/RowError"}},"startedAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time"},"durationMs":{"type":"integer","format":"int64"}}},"RowError":{"type":"object","properties":{"rowNumber":{"type":"integer","format":"int32"},"tenantId":{"type":"string"},"errorMessage":{"type":"string"}}},"SecondaryCountryRequest":{"type":"object","properties":{"country":{"type":"string","maxLength":2,"minLength":2}},"required":["country"]},"RegisterRequest":{"type":"object","default":null,"description":"Self-service registration — creates a tenant and a DEMO API key","properties":{"email":{"type":"string","format":"email","default":"","description":"Contact email address","example":"dev@acme.com","minLength":1},"companyName":{"type":"string","default":"","description":"Company or project name","example":"Acme Corp","maxLength":100,"minLength":2},"domain":{"type":"string","default":"","description":"Optional website domain","example":"acme.com"}},"required":["companyName","email"]},"RegisterResponse":{"type":"object","default":null,"description":"Registration response with tenant info and DEMO API key","properties":{"tenantId":{"type":"string","default":"","description":"Tenant ID"},"tenantCode":{"type":"string","default":"","description":"Tenant code (derived from email)"},"companyName":{"type":"string","default":"","description":"Company name"},"apiKey":{"type":"string","default":"","description":"Raw DEMO API key — shown ONLY ONCE","example":"dx_live_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"},"keyPrefix":{"type":"string","default":"","description":"API key prefix for identification"},"plan":{"type":"string","default":"","description":"Plan assigned","example":"DEMO"},"dailyLimit":{"type":"integer","format":"int32","default":"","description":"Daily request limit","example":100},"monthlyLimit":{"type":"integer","format":"int32","default":"","description":"Monthly request limit","example":1000},"createdAt":{"type":"string","format":"date-time","default":"","description":"Registration timestamp"}}},"RecoverRequest":{"type":"object","default":null,"description":"API key recovery request — triggers recovery email to registered address","properties":{"email":{"type":"string","format":"email","default":"","description":"The email used during registration","example":"dev@acme.com","minLength":1}},"required":["email"]},"TenantTunisiaSettingsPatchDto":{"type":"object","properties":{"ttnMemberId":{"type":"string","maxLength":64,"minLength":0},"ttnSenderId":{"type":"string","maxLength":64,"minLength":0},"ttnAdhesionStatus":{"type":"string","maxLength":32,"minLength":0},"matriculeFiscalTn":{"type":"string","maxLength":32,"minLength":0},"rneNumber":{"type":"string","maxLength":32,"minLength":0},"declaredIp":{"type":"string","maxLength":45,"minLength":0},"signingBackend":{"type":"string","maxLength":32,"minLength":0},"ngsignOrganizationId":{"type":"string","maxLength":128,"minLength":0},"signingCertRef":{"type":"string","maxLength":256,"minLength":0},"signingCertExpiry":{"type":"string","format":"date"},"signingCertType":{"type":"string","maxLength":32,"minLength":0}}},"TenantTunisiaSettingsDto":{"type":"object","properties":{"ttnMemberId":{"type":"string"},"ttnSenderId":{"type":"string"},"ttnProductionReady":{"type":"boolean"},"ttnAdhesionStatus":{"type":"string"},"matriculeFiscalTn":{"type":"string"},"rneNumber":{"type":"string"},"declaredIp":{"type":"string"},"signingBackend":{"type":"string"},"ngsignOrganizationId":{"type":"string"},"signingCertRef":{"type":"string"},"signingCertExpiry":{"type":"string","format":"date"},"signingCertType":{"type":"string"}}},"TtnEmailTemplate":{"type":"object","properties":{"to":{"type":"string"},"cc":{"type":"string"},"subject":{"type":"string"},"body":{"type":"string"}}},"SignatureWalletHistory":{"type":"object","properties":{"id":{"type":"string"},"tenantId":{"type":"string"},"changedAt":{"type":"string","format":"date-time"},"changedBy":{"type":"string"},"changeType":{"type":"string","enum":["CREATE","METHOD_CHANGE","CREDENTIALS_UPDATE","STATUS_CHANGE","CERTIFICATE_RENEWED","TTN_CONFIG","TTN_SUBMISSION_TEST","TTN_APPROVAL_TEST","TTN_SUBMISSION_PROD","TTN_APPROVAL_PROD","TTN_REJECTION","ENTERPRISE_ID_EMAIL_SENT","ENTERPRISE_ID_ACTIVATED"]},"oldMethod":{"type":"string","enum":["DIGIGO","ENTERPRISE_ID_SEAL","ID_TRUST_USB","NONE"]},"newMethod":{"type":"string","enum":["DIGIGO","ENTERPRISE_ID_SEAL","ID_TRUST_USB","NONE"]},"oldStatus":{"type":"string","enum":["PENDING","PENDING_TTN_APPROVAL","ACTIVE","EXPIRED","REVOKED","SUSPENDED"]},"newStatus":{"type":"string","enum":["PENDING","PENDING_TTN_APPROVAL","ACTIVE","EXPIRED","REVOKED","SUSPENDED"]},"oldTtnSubmissionStatus":{"type":"string","enum":["NOT_SUBMITTED","EMAIL_TEMPLATE_GENERATED","SUBMITTED_WAITING_TEST","TEST_APPROVED","SUBMITTED_WAITING_PROD","PROD_APPROVED","REJECTED"]},"newTtnSubmissionStatus":{"type":"string","enum":["NOT_SUBMITTED","EMAIL_TEMPLATE_GENERATED","SUBMITTED_WAITING_TEST","TEST_APPROVED","SUBMITTED_WAITING_PROD","PROD_APPROVED","REJECTED"]},"notes":{"type":"string"}}},"BankTransaction":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenantId":{"type":"string"},"transactionDate":{"type":"string","format":"date"},"valueDate":{"type":"string","format":"date"},"amount":{"type":"number"},"currency":{"type":"string"},"rawLabel":{"type":"string"},"normalizedLabel":{"type":"string"},"counterpartyName":{"type":"string"},"transactionType":{"type":"string"},"bankFormat":{"type":"string"},"bankProfile":{"type":"string"},"vatHt":{"type":"number"},"vatTotal":{"type":"number"},"vatBreakdown":{"type":"object","additionalProperties":{}},"rawMetadata":{"type":"object","additionalProperties":{}},"importBatchId":{"type":"string","format":"uuid"},"importedAt":{"type":"string","format":"date-time"},"matched":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}}},"PageBankTransaction":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/BankTransaction"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"numberOfElements":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"empty":{"type":"boolean"}}},"PageableObject":{"type":"object","properties":{"paged":{"type":"boolean"},"pageNumber":{"type":"integer","format":"int32"},"pageSize":{"type":"integer","format":"int32"},"offset":{"type":"integer","format":"int64"},"sort":{"$ref":"#/components/schemas/SortObject"},"unpaged":{"type":"boolean"}}},"SortObject":{"type":"object","properties":{"sorted":{"type":"boolean"},"empty":{"type":"boolean"},"unsorted":{"type":"boolean"}}},"PageReconciliationMatch":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/ReconciliationMatch"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"numberOfElements":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"empty":{"type":"boolean"}}},"InvitationPreviewResponse":{"type":"object","properties":{"groupName":{"type":"string"},"inviterName":{"type":"string"},"role":{"type":"string","enum":["GROUP_ADMIN","GROUP_VIEWER"]},"memberCount":{"type":"integer","format":"int64"},"expiresAt":{"type":"string","format":"date-time"}}},"PagedResponseGroupResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/GroupResponse"}},"nextCursor":{"type":"string"},"pageSize":{"type":"integer","format":"int32"},"hasMore":{"type":"boolean"}}},"TenantStatsResponse":{"type":"object","properties":{"tenantId":{"type":"string"},"tenantName":{"type":"string"},"currency":{"type":"string"},"invoiceCount":{"type":"integer","format":"int64"},"revenue":{"type":"number"},"vat":{"type":"number"}}},"PagedResponseTenantSummary":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TenantSummary"}},"nextCursor":{"type":"string"},"pageSize":{"type":"integer","format":"int32"},"hasMore":{"type":"boolean"}}},"TenantSummary":{"type":"object","properties":{"id":{"type":"string"},"code":{"type":"string"},"name":{"type":"string"}}},"AggregationResponse":{"type":"object","properties":{"groupId":{"type":"string","format":"uuid"},"tenantCount":{"type":"integer","format":"int64"},"invoiceCountTotal":{"type":"integer","format":"int64"},"dominantCurrency":{"type":"string"},"byCurrency":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/CurrencyAggregationResponse"}},"computedAt":{"type":"string","format":"date-time"}}},"CurrencyAggregationResponse":{"type":"object","properties":{"currency":{"type":"string"},"invoiceCount":{"type":"integer","format":"int64"},"totalRevenue":{"type":"number"},"totalVat":{"type":"number"}}},"PagedResponseTransferResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TransferResponse"}},"nextCursor":{"type":"string"},"pageSize":{"type":"integer","format":"int32"},"hasMore":{"type":"boolean"}}},"PagedResponseInvitationResponse":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/InvitationResponse"}},"nextCursor":{"type":"string"},"pageSize":{"type":"integer","format":"int32"},"hasMore":{"type":"boolean"}}},"PageDocumentMetadata":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/DocumentMetadata"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"numberOfElements":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"empty":{"type":"boolean"}}},"PageCustomerResponse":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/CustomerResponse"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"numberOfElements":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"empty":{"type":"boolean"}}},"Defaults":{"type":"object","properties":{"language":{"type":"string"},"currency":{"type":"string"},"compliance":{"type":"string"}}},"FormatDto":{"type":"object","properties":{"code":{"type":"string"},"wireCode":{"type":"string"},"displayName":{"type":"string"},"family":{"type":"string"},"standard":{"type":"string"},"clearanceStrict":{"type":"boolean"},"en16931Compatible":{"type":"boolean"}}},"CountryDto":{"type":"object","properties":{"iso":{"type":"string"},"displayName":{"type":"string"},"currency":{"type":"string"}}},"CountryMetadataDto":{"type":"object","properties":{"iso":{"type":"string"},"displayName":{"type":"string"},"currency":{"type":"string"},"currencyDecimals":{"type":"integer","format":"int32"},"region":{"type":"string"},"languages":{"type":"array","items":{"type":"string"}},"taxLabel":{"type":"string"},"defaultTaxRate":{"type":"number"},"taxRates":{"type":"array","items":{"type":"number"}},"taxIdLabel":{"type":"string"},"taxIdPlaceholder":{"type":"string"},"vatLabel":{"type":"string"},"vatPlaceholder":{"type":"string"}}},"CountryFormatsDto":{"type":"object","properties":{"iso":{"type":"string"},"displayName":{"type":"string"},"currency":{"type":"string"},"primaryFormat":{"$ref":"#/components/schemas/FormatDto"},"compatibleSecondaryFormats":{"type":"array","items":{"$ref":"#/components/schemas/FormatDto"}},"clearanceStrict":{"type":"boolean"}}},"DocumentArchive":{"type":"object","properties":{"id":{"type":"string"},"documentId":{"type":"string"},"tenantId":{"type":"string"},"sequenceNumber":{"type":"integer","format":"int64"},"documentHash":{"type":"string"},"previousHash":{"type":"string"},"chainHash":{"type":"string"},"archivedAt":{"type":"string","format":"date-time"},"pdfSizeBytes":{"type":"integer","format":"int64"},"xmlSizeBytes":{"type":"integer","format":"int64"},"xmlHash":{"type":"string"},"pdfHash":{"type":"string"},"metadata":{"type":"object","additionalProperties":{}}}},"PageDocumentArchive":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/DocumentArchive"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"numberOfElements":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"empty":{"type":"boolean"}}},"ApiKeyResponse":{"type":"object","default":null,"description":"API key details (raw key value is never included)","properties":{"id":{"type":"string","default":"","description":"Unique identifier"},"keyPrefix":{"type":"string","default":"","description":"Key prefix for identification","example":"dx_live_a1b2c3d4"},"name":{"type":"string","default":"","description":"Human-readable name","example":"POS Integration Key"},"plan":{"type":"string","default":"","description":"API plan tier","example":"DEMO"},"active":{"type":"boolean","default":false,"description":"Whether this key is active"},"dailyLimit":{"type":"integer","format":"int32","default":"","description":"Maximum requests per day"},"monthlyLimit":{"type":"integer","format":"int32","default":"","description":"Maximum requests per month"},"dailyCount":{"type":"integer","format":"int32","default":"","description":"Requests made today"},"monthlyCount":{"type":"integer","format":"int32","default":"","description":"Requests made this month"},"lastUsedAt":{"type":"string","format":"date-time","default":"","description":"Last API call timestamp"},"expiresAt":{"type":"string","format":"date-time","default":"","description":"Key expiration (null if no expiration)"},"createdAt":{"type":"string","format":"date-time","default":"","description":"Creation timestamp"}}},"AuditEvent":{"type":"object","properties":{"id":{"type":"string"},"tenantId":{"type":"string"},"action":{"type":"string"},"resourceType":{"type":"string"},"resourceId":{"type":"string"},"apiKeyPrefix":{"type":"string"},"correlationId":{"type":"string"},"ipAddress":{"type":"string"},"userAgent":{"type":"string"},"details":{"type":"object","additionalProperties":{}},"createdAt":{"type":"string","format":"date-time"}}},"PageAuditEvent":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/AuditEvent"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"numberOfElements":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"empty":{"type":"boolean"}}},"PageSecurityAuditEventDto":{"type":"object","properties":{"totalElements":{"type":"integer","format":"int64"},"totalPages":{"type":"integer","format":"int32"},"pageable":{"$ref":"#/components/schemas/PageableObject"},"size":{"type":"integer","format":"int32"},"content":{"type":"array","items":{"$ref":"#/components/schemas/SecurityAuditEventDto"}},"number":{"type":"integer","format":"int32"},"sort":{"$ref":"#/components/schemas/SortObject"},"numberOfElements":{"type":"integer","format":"int32"},"first":{"type":"boolean"},"last":{"type":"boolean"},"empty":{"type":"boolean"}}},"SecurityAuditEventDto":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"eventType":{"type":"string"},"tenantIdHash":{"type":"string"},"userIdHash":{"type":"string"},"ipAddress":{"type":"string"},"userAgent":{"type":"string"},"timestampUtc":{"type":"string","format":"date-time"},"success":{"type":"boolean"},"failureReason":{"type":"string"},"metadata":{"type":"object","additionalProperties":{}}}},"UsageResponse":{"type":"object","default":null,"description":"API usage statistics and daily history","properties":{"plan":{"type":"string","default":"","description":"Current plan","example":"DEMO"},"dailyLimit":{"type":"integer","format":"int32","default":"","description":"Daily limit"},"monthlyLimit":{"type":"integer","format":"int32","default":"","description":"Monthly limit"},"dailyUsed":{"type":"integer","format":"int32","default":"","description":"Requests used today"},"monthlyUsed":{"type":"integer","format":"int32","default":"","description":"Requests used this month"},"totalDocuments":{"type":"integer","format":"int64","default":"","description":"Total documents generated all time"},"todayDocuments":{"type":"integer","format":"int64","default":"","description":"Documents generated today"},"documentsByType":{"type":"object","additionalProperties":{"type":"integer","format":"int64"},"default":"","description":"Documents by type breakdown"},"timestamp":{"type":"string","format":"date-time","default":"","description":"Timestamp of the usage snapshot"}}},"AccountInfoResponse":{"type":"object","default":null,"description":"Account information for the current API key's tenant","properties":{"tenantId":{"type":"string","default":"","description":"Tenant ID"},"companyName":{"type":"string","default":"","description":"Company name"},"plan":{"type":"string","default":"","description":"Current plan","example":"DEMO"},"active":{"type":"boolean","default":false,"description":"Whether the API key is active"},"dailyLimit":{"type":"integer","format":"int32","default":"","description":"Daily request limit"},"monthlyLimit":{"type":"integer","format":"int32","default":"","description":"Monthly request limit"},"dailyUsed":{"type":"integer","format":"int32","default":"","description":"Requests made today"},"monthlyUsed":{"type":"integer","format":"int32","default":"","description":"Requests made this month"},"totalDocuments":{"type":"integer","format":"int64","default":"","description":"Total documents generated"},"monthlyDocuments":{"type":"integer","format":"int64","default":"","description":"Documents generated in the current calendar month (UTC)"},"documentsByType":{"type":"object","additionalProperties":{"type":"integer","format":"int64"},"default":"","description":"Documents by type breakdown"},"createdAt":{"type":"string","format":"date-time","default":"","description":"Account creation date"},"trialEndsAt":{"type":"string","format":"date-time","default":"","description":"End of trial period (null for paid plans). Computed as tenant.createdAt + 30 days for TRIAL/DEMO plans."},"allowedCountries":{"type":"array","default":"","description":"ISO alpha-2 country codes covered by the current plan. Empty for READ_ONLY. Sprint OMEGA-2.","items":{"type":"string"}},"essentialSecondaryCountry":{"type":"string","default":"","description":"Essential plan only: the second country picked by the tenant (besides FR). Null for other plans."},"essentialCountryChangedAt":{"type":"string","format":"date-time","default":"","description":"Last time the Essential tenant changed essentialSecondaryCountry. Drives the 30-day cooldown."}}}},"securitySchemes":{"X-Doxnex-Api-Key":{"type":"apiKey","description":"Doxnex API Key (prefix: dx_live_)","name":"X-Doxnex-Api-Key","in":"header"}}}}