Jeden generovaný OpenAPI 3.1 dokument so 195 operáciami, ktorý popisuje naraz povrch portálu, api-internal aj api-public a je dostupný len v dev a test prostredí.
YAML syntax error — Excessive alias count indicates a resource exhaustion attack. Fix the document in the catalog repository — until then the raw file is shown below.
services/portal-web/api/0.0.0/openapi.yaml
services/portal-web/api/0.0.0/openapi.yaml
openapi: 3.1.0
info:
title: Gordulitch Portal API (internal)
version: 0.0.0
description: "Internal, dev/test-only documentation of the portal API surface
(Plan 122). Never served in prod. Covers TWO distinct provenances, badged
per-operation via `x-source`: our own Portal Next.js route handlers
(`x-source: portal`) and the Supabase PostgREST RPC catalog (`x-source:
postgrest`, invoked as `POST /rest/v1/rpc/<fn>`). Responses and route-less
request schemas are hand-authored (not runtime-validated) — see plan §8a for
the full-zod-retrofit follow-up that would make this 100% auto-derived."
tags:
- name: admin-incidents
description: NIS2 incident lifecycle — acknowledge, classify, notify,
prioritize, resolve.
- name: admin-quarantine
description: Quarantined inbound entries and storage garbage-collection.
- name: admin-retention-dsar
description: Retention sweeps, DSAR export, and tenant pseudonymization.
- name: admin-users
description: User/role/subscription-type provisioning and lifecycle (portal
routes + `/rest/v1/rpc`).
- name: agent-m2m
description: Machine-to-machine agent lease/ack/ingest surface (api-key/mTLS —
documentation-only).
- name: audit
description: Append-only audit log search/export and integrity status (portal
routes + `/rest/v1/rpc`).
- name: auth
description: Sign-in completion, auth-event recording, current-permissions
projection (all `/rest/v1/rpc`).
- name: billing
description: Settings › Predplatné self-service — the tenant’s OWN payment
method (SetupIntent + default PM), package change (prorated, SCA-aware),
and subscription-invoice PDF (the portal’s OWN SaaS billing, ≠ eFaktúra).
- name: dlq
description: Dead-letter-queue list/requeue/discard RPCs.
- name: evidence
description: The unified 10-year receipt-evidence ledger (MLS + TDD receipts) —
browse and download.
- name: health
description: "Unauthenticated platform endpoints: the liveness + shallow
DB-readiness probe, and the CSP-violation collector (Plan 226)."
- name: inbound
description: Received PEPPOL invoices — list/detail, XML + TDD download.
- name: invoices-outbound
description: Outbound eFaktúra XML — upload, list/detail, retry-send,
attachments, TDD download.
- name: knowledge-base
description: Admin-editable bilingual help articles behind the "i" info modal
(portal read route + `/rest/v1/rpc` CRUD).
- name: legal-hold
description: Legal-hold place/release/report RPCs (retention-floor override).
- name: org
description: Organization self-service settings — a tenant admin’s own org
detail, participant IDs, and users (portal route + `/rest/v1/rpc`).
- name: oxalis-monitoring
description: Oxalis Access Point health snapshots, history, logs, and on-demand
collection.
- name: oxalis-ops
description: Ops actions against the Adapter's poisoned-inbound and
stuck-outbound lanes.
- name: participants
description: PEPPOL participant-identifier lookup and admin management (portal
route + `/rest/v1/rpc`).
- name: profile
description: Settings › Profile self-service — the caller’s OWN name/phone,
avatar upload, and password change (portal routes + `/rest/v1/rpc`).
- name: reports
description: Transport-exceptions, summary, and export admin/tenant reports.
- name: settings
description: The system_setting registry list/update RPCs.
- name: status
description: Consolidated per-document and paginated status projections (FR-52/UC-18).
- name: tenants
description: Tenant create/update/status RPCs.
- name: trace
description: End-to-end document trace across ingest → validation → send/AS4 →
MLS → TDD + audit legs.
- name: validation-rules
description: Validation-rules registry versioning + deploy/revert (portal route
+ `/rest/v1/rpc`).
- name: webhooks
description: Adapter-originated inbound/send-status webhooks (HMAC service-auth
— documentation-only).
- name: workers
description: Worker fleet oversight — heartbeats, queue depth/peek, command
history, cooperative restart.
x-tagGroups:
- name: Portal Next.js API
tags:
- admin-incidents
- admin-quarantine
- admin-retention-dsar
- admin-users
- audit
- auth
- billing
- evidence
- health
- inbound
- invoices-outbound
- knowledge-base
- org
- oxalis-monitoring
- oxalis-ops
- participants
- profile
- reports
- status
- trace
- validation-rules
- workers
- name: Supabase PostgREST RPC
tags:
- dlq
- legal-hold
- settings
- tenants
- name: Service-auth / M2M (docs-only)
tags:
- agent-m2m
- webhooks
paths:
/api/v1/admin/archive-handovers/{id}/confirm-out-of-band:
post:
tags:
- admin-retention-dsar
summary: Record an archive hand-over confirmed outside the application
description: "The LOUD arm of the hand-over interlock: the provider records a
receipt obtained by e-mail, ticket or signature, so that an unresponsive
client cannot block disposal forever. Mandatory external confirmation
reference + reason; audited under a DISTINCT action and additionally
recorded in the RM-26 security_event sink. ⛔ Plan 294 OQ-H: REFUSED with
409 notice_series_incomplete unless a documented series of notices is
already on record for this hand-over (at least
archive_handover_out_of_band_min_notices notices, the earliest at least
archive_handover_out_of_band_window_days old) — fail-closed, never a
warning."
operationId: post_api_v1_admin_archive_handovers_id_confirm_out_of_band
x-source: portal
x-service:
- api-internal
x-rbac: retention:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminArchiveHandoversIdConfirmOutOfBandReq\
uest"
responses:
"200":
description: The hand-over is confirmed (write-once)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: &a1
$ref: "#/components/schemas/ApiError"
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/audit-integrity/status:
get:
tags:
- audit
summary: Admin "Audit integrity" card data
description: Latest chain-verifier run per kind, WORM-export manifest tail +
lag, anchor-divergence signal. Reads the security_invoker
v_audit_integrity_dashboard view. Aggregate/hash-metadata only — zero
PII.
operationId: get_api_v1_admin_audit_integrity_status
x-source: portal
x-service:
- api-internal
x-rbac: audit_log:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Audit-integrity dashboard payload
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/bottleneck-check:
get:
tags:
- workers
summary: Latest bottleneck-check runs + the newest run’s per-signal evidence
description: "Plan 264: the dark ops.bottleneck_check_run ledger, read through
the service-role client AFTER the gate. Verdict ∈
none|c5|adapter_sender|adapter_bridge|worker_send|worker_validation|sup\
abase|peer|indeterminate. A deny is a MASKED 404 (never 403) + a
masked_404 security-event, so a tenant member cannot distinguish this
cross-tenant ops route from a non-existent one. Not audited (queue
depths, counts and component verdicts only — no tenant data and no
participant identifier; the WRITE twin IS audited)."
operationId: get_api_v1_admin_bottleneck_check
x-source: portal
x-service:
- portal
x-rbac: worker_ops:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
parameters:
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 50
responses:
"200":
description: "{ runs: BottleneckRun[], latest: (BottleneckRun & { signals }) |
null }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — the masked deny for a non-provider or a caller without
worker_ops:read.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/bottleneck-check/run:
post:
tags:
- workers
summary: Run the bottleneck check now (audited manual trigger)
description: "Plan 264: the SESSION-authenticated twin of the internal pg_cron
trigger — same in-process orchestrator, but with a real actor.
`bottleneck_check_run_requested` audits
(worker_ops.bottleneck_check_run) on the CALLER’s client BEFORE the
sweep starts and returns auth.uid(); a failed audit write ⇒ 503 and NO
run. A manual run bypasses only the INTERVAL gate — the single-flight
claim still applies, so `ran:false` (a run already in flight) is a
normal 200. Read-only against every business table; it never restarts a
worker, requeues a message or touches an Adapter queue."
operationId: post_api_v1_admin_bottleneck_check_run
x-source: portal
x-service:
- api-internal
x-rbac: worker_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: false
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminBottleneckCheckRunRequest"
responses:
"200":
description: "{ ran, runId, status, verdict? } | { ran: false, skippedReason }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"503":
description: audit_failed — the audit row did not land; the sweep was NOT started.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/dsar/{id}/export:
get:
tags:
- admin-retention-dsar
summary: Download the GDPR Art. 15 subject-access export
description: Versioned gordulitch-dsar-v1 JSON attachment. Records export_sha256
on the request row.
operationId: get_api_v1_admin_dsar_id_export
x-source: portal
x-service:
- portal
x-rbac: dsar:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: application/json DSAR export attachment
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/incidents:
post:
tags:
- admin-incidents
summary: Manually open an incident
description: §5.2 human-detected path (e.g. a DP-01 mis-mapping found in
triage). category/severity admin-chosen; nis2_status starts
not_assessed.
operationId: post_api_v1_admin_incidents
x-source: portal
x-service:
- api-internal
x-rbac: incident:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminIncidentsRequest"
responses:
"200":
description: "{ id: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/incidents/{id}/acknowledge:
post:
tags:
- admin-incidents
summary: Acknowledge an open incident
description: open -> acknowledged (the in-product 'stop re-alerting'). P0002 ->
404, P0001 (not open) -> 409.
operationId: post_api_v1_admin_incidents_id_acknowledge
x-source: portal
x-service:
- api-internal
x-rbac: incident:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: not_open — the incident is not in the open state.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/incidents/{id}/classify:
post:
tags:
- admin-incidents
summary: Record the NIS2 reportability decision
description: A recorded human decision, never automatic. Rationale mandatory for
a non-not_assessed decision (400); classify of a resolved incident ->
409.
operationId: post_api_v1_admin_incidents_id_classify
x-source: portal
x-service:
- api-internal
x-rbac: incident:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminIncidentsIdClassifyRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: The incident is already resolved (terminal).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/incidents/{id}/notify:
post:
tags:
- admin-incidents
summary: Send a tenant-facing incident notice (RM-15)
description: "Fail-closed content contract: canned template_key whitelist +
per-template params whitelist, reference document must belong to the
target tenant, target must be an active customer tenant. 400 on contract
violation; 403 on auth failure."
operationId: post_api_v1_admin_incidents_id_notify
x-source: portal
x-service:
- api-internal
x-rbac: incident:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminIncidentsIdNotifyRequest"
responses:
"200":
description: "{ notificationId: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/incidents/{id}/priority:
post:
tags:
- admin-incidents
summary: Set the business priority (p1–p3)
description: Priority ≠ severity (UC-14). Allowed while not resolved. 400 empty;
404 not found; 409 resolved.
operationId: post_api_v1_admin_incidents_id_priority
x-source: portal
x-service:
- api-internal
x-rbac: incident:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminIncidentsIdPriorityRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: The incident is already resolved (terminal).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/incidents/{id}/resolve:
post:
tags:
- admin-incidents
summary: Resolve an incident
description: "Fail-closed: raises (409) unless nis2_status <> not_assessed;
resolved is terminal; empty resolution -> 400."
operationId: post_api_v1_admin_incidents_id_resolve
x-source: portal
x-service:
- api-internal
x-rbac: incident:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminIncidentsIdResolveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: Fail-closed — cannot resolve while nis2_status is not_assessed, or
already resolved.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/{instance}/collector-status:
get:
tags:
- oxalis-monitoring
summary: Auto-collection status (P-043)
description: Derived Mode (mock/mock_cron_live/live/not_configured),
latest-snapshot Freshness (amber/red thresholds), and the
oxalis-health-snapshot cron-job health. Never snapshot content.
operationId: get_api_v1_admin_oxalis_instance_collector_status
x-source: portal
x-service:
- portal
x-rbac: oxalis_monitoring:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: instance
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ mode, freshness, cronJobHealth }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/{instance}/history:
get:
tags:
- oxalis-monitoring
summary: Snapshot time series (availability + cert trend)
operationId: get_api_v1_admin_oxalis_instance_history
x-source: portal
x-service:
- portal
x-rbac: oxalis_monitoring:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
parameters:
- name: instance
in: path
required: true
schema:
type: string
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 9007199254740991
- name: since
in: query
required: false
schema:
type: string
responses:
"200":
description: Array of oxalis_health_snapshot rows
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/{instance}/logs:
get:
tags:
- oxalis-monitoring
summary: Bounded, PII-scrubbed log tail
operationId: get_api_v1_admin_oxalis_instance_logs
x-source: portal
x-service:
- portal
x-rbac: oxalis_logs:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: instance
in: path
required: true
schema:
type: string
- name: level
in: query
required: false
schema:
type: string
- name: since
in: query
required: false
schema:
type: string
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 9007199254740991
responses:
"200":
description: Bounded array of log lines (PII-scrubbed at source)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/{instance}/logs/export:
get:
tags:
- oxalis-monitoring
summary: Same log tail as a CSV download
operationId: get_api_v1_admin_oxalis_instance_logs_export
x-source: portal
x-service:
- portal
x-rbac: oxalis_logs:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: instance
in: path
required: true
schema:
type: string
- name: level
in: query
required: false
schema:
type: string
- name: since
in: query
required: false
schema:
type: string
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 9007199254740991
responses:
"200":
description: text/csv attachment
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/{instance}/refresh:
post:
tags:
- oxalis-monitoring
summary: On-demand collector pull
description: One append-only snapshot (records a failed probe too, up=false +
probe_error).
operationId: post_api_v1_admin_oxalis_instance_refresh
x-source: portal
x-service:
- api-internal
x-rbac: oxalis_monitoring:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
parameters:
- name: instance
in: path
required: true
schema:
type: string
responses:
"200":
description: The newly recorded oxalis_health_snapshot row
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/{instance}/status:
get:
tags:
- oxalis-monitoring
summary: Latest health snapshot
description: Includes cert-expiry/stale thresholds. Unknown/invisible instance
code -> 404.
operationId: get_api_v1_admin_oxalis_instance_status
x-source: portal
x-service:
- portal
x-rbac: oxalis_monitoring:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
parameters:
- name: instance
in: path
required: true
schema:
type: string
responses:
"200":
description: Latest oxalis_health_snapshot row + derived thresholds
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/instances:
get:
tags:
- oxalis-monitoring
summary: List monitored Access Points
description: Multi-instance ready; `local` seeded.
operationId: get_api_v1_admin_oxalis_instances
x-source: portal
x-service:
- portal
x-rbac: oxalis_monitoring:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Array of oxalis_instance rows
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/ops/inbound/poisoned:
get:
tags:
- oxalis-ops
summary: List the Adapter's poisoned inbound entries
description: webhookTxId/ageSeconds/archived/lastError via the S1 admin-ops
client. 503 admin_ops_disabled when OXALIS_ADMIN_SECRET is unset.
operationId: get_api_v1_admin_oxalis_ops_inbound_poisoned
x-source: portal
x-service:
- portal
x-rbac: oxalis_admin_ops:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Array of poisoned inbound entries
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"502":
description: adapter_unreachable — the Adapter admin-ops surface did not answer.
content:
application/json:
schema: *a1
"503":
description: admin_ops_disabled — OXALIS_ADMIN_SECRET is unset.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/ops/inbound/poisoned/{id}/purge:
delete:
tags:
- oxalis-ops
summary: Purge a poisoned inbound entry — the only deletion path
description: 409 not_archived unless archived.json exists (archive-then-purge;
always 409 until the WORM archive runs).
operationId: delete_api_v1_admin_oxalis_ops_inbound_poisoned_id_purge
x-source: portal
x-service:
- api-internal
x-rbac: oxalis_admin_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: Adapter purge acknowledgement
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: not_archived — the WORM archive (archived.json) has not run yet.
content:
application/json:
schema: *a1
"502":
description: adapter_unreachable.
content:
application/json:
schema: *a1
"503":
description: admin_ops_disabled — OXALIS_ADMIN_SECRET is unset (or audit_failed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/ops/inbound/poisoned/{id}/requeue:
post:
tags:
- oxalis-ops
summary: Requeue a poisoned inbound entry to the Adapter's pending/ lane
description: "{id} N17-validated before URL construction. Adapter status passed
through honestly (404 unknown; 429 rate-capped)."
operationId: post_api_v1_admin_oxalis_ops_inbound_poisoned_id_requeue
x-source: portal
x-service:
- api-internal
x-rbac: oxalis_admin_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: Adapter requeue acknowledgement
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"429":
description: rate-capped — the Adapter status is passed through honestly.
content:
application/json:
schema: *a1
"502":
description: adapter_unreachable.
content:
application/json:
schema: *a1
"503":
description: admin_ops_disabled — OXALIS_ADMIN_SECRET is unset (or audit_failed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/ops/outbound/{key}/release:
post:
tags:
- oxalis-ops
summary: Release a stuck outbound idempotency key for a portal re-send
description: The Adapter never re-transmits. Client always signs confirm=true;
{key} allowlist-validated. The Adapter 409 is a single undistinguishable
not_releasable.
operationId: post_api_v1_admin_oxalis_ops_outbound_key_release
x-source: portal
x-service:
- api-internal
x-rbac: oxalis_admin_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: key
in: path
required: true
schema:
type: string
responses:
"200":
description: Adapter release acknowledgement
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: not_releasable — a single undistinguishable Adapter conflict.
content:
application/json:
schema: *a1
"502":
description: adapter_unreachable.
content:
application/json:
schema: *a1
"503":
description: admin_ops_disabled — OXALIS_ADMIN_SECRET is unset (or audit_failed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/oxalis/ops/outbound/stuck:
get:
tags:
- oxalis-ops
summary: List the Adapter's stuck outbound idempotency rows
description: idempotencyKey/transmissionId/ageSeconds.
operationId: get_api_v1_admin_oxalis_ops_outbound_stuck
x-source: portal
x-service:
- portal
x-rbac: oxalis_admin_ops:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Array of stuck outbound idempotency rows
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"502":
description: adapter_unreachable.
content:
application/json:
schema: *a1
"503":
description: admin_ops_disabled — OXALIS_ADMIN_SECRET is unset.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/quarantine/{id}/discard:
post:
tags:
- admin-quarantine
summary: Provider manually discards a quarantine item
description: Flip status='discarded' + audit, then delete the payload object
only — the AS4 receipt_ref is exempt and never deleted (V5).
operationId: post_api_v1_admin_quarantine_id_discard
x-source: portal
x-service:
- api-internal
x-rbac: inbound_quarantine:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/quarantine/{id}/resolve:
post:
tags:
- admin-quarantine
summary: Resolve an open quarantine item to an explicit tenant
description: Move the payload _quarantine/…→tenant path, create the
inbound_document (delivery_pending), carry receipt_ref, mark 'resolved'
(M2).
operationId: post_api_v1_admin_quarantine_id_resolve
x-source: portal
x-service:
- api-internal
x-rbac: inbound_quarantine:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminQuarantineIdResolveRequest"
responses:
"200":
description: void (inbound_document created)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: not_open — the quarantine item is not in the open state.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/reports/billing-reconciliation:
get:
tags:
- reports
summary: Provider-only Stripe billing-reconciliation drift report (Plan 199 S4b)
description: "Reads the dark ops.billing_recon_run ledger the Plan 199 sweep
writes: the latest ?limit runs (summary columns) plus the newest — or
?run=<id>-selected — run's findings. ?format=csv streams the same
findings as CSV. Provider + billing:read; a caller failing that gate
gets a MASKED 404 (never 403) — a tenant member holding their own
billing:read must not be able to distinguish this cross-tenant report
from a missing route. Audited sensitive read
(billing.recon_report_viewed) BEFORE any bytes are built."
operationId: get_api_v1_admin_reports_billing_reconciliation
x-source: portal
x-service:
- portal
x-rbac: provider + billing:read (masked 404 on deny, not 403)
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: limit
in: query
required: false
schema:
type: string
- name: run
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: format
in: query
required: false
schema:
type: string
enum:
- csv
responses:
"200":
description: Recent runs + selected run findings (JSON), or text/csv attachment
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: "not_found — masked: either the caller is not a provider / lacks
billing:read, or (rare) an unresolved ?run id. Deliberately
indistinguishable from a missing route (anti-leakage)."
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/reports/transport-exceptions:
get:
tags:
- reports
summary: Unified admin exceptions view (Plan 111 S6)
description: Adapter poisoned/stuck counts, AP quarantine, portal quarantine,
DLQ depth, aged sent_to_* documents, orphan MLS + held-unparsed-MLS
Storage count, and a capped sample of unfetched inbound evidence. Each
block is a cheap count/oldest-age read — never raw document content.
operationId: get_api_v1_admin_reports_transport_exceptions
x-source: portal
x-service:
- api-internal
x-rbac: composite (oxalis_admin_ops, oxalis_monitoring, inbound_quarantine,
dlq_ops, outbound_document — no all-or-nothing gate)
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Composite exceptions dashboard payload
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/retention:
get:
tags:
- admin-retention-dsar
summary: Retention report
description: Per-class last-run summaries from retention_sweep_run
(candidate/held-skip/deleted/anomaly counts, cutoff, mode), matrix
status, gate status, next-run schedule. Metadata only — never invoice
XML.
operationId: get_api_v1_admin_retention
x-source: portal
x-service:
- portal
x-rbac: retention:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Retention matrix + gate status report
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/retention/run:
post:
tags:
- admin-retention-dsar
summary: Trigger an on-demand retention sweep
description: A destructive run executes only when the two-key gate is open
(RETENTION_DESTRUCTIVE_ENABLED env AND retention_destructive_mode
setting); otherwise downgrades to dry-run.
operationId: post_api_v1_admin_retention_run
x-source: portal
x-service:
- api-internal
x-rbac: retention:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminRetentionRunRequest"
responses:
"200":
description: PII-free sweep result counts
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/security-events:
get:
tags:
- admin-incidents
summary: Filterable read-only list of the RM-26 security_event sink
description: kind ∈ auth_401/authz_403/masked_404/hmac_reject/rate_limited;
filters kind/route/from/to/limit, default 100 cap 500. A 401/403 on this
route is itself recorded into the sink.
operationId: get_api_v1_admin_security_events
x-source: portal
x-service:
- portal
x-rbac: security_event:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
parameters:
- name: kind
in: query
required: false
schema:
type: string
enum:
- auth_401
- authz_403
- masked_404
- hmac_reject
- rate_limited
- name: route
in: query
required: false
schema:
type: string
- name: from
in: query
required: false
schema:
type: string
- name: to
in: query
required: false
schema:
type: string
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 500
responses:
"200":
description: Array of security_event rows
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/storage-gc/run:
post:
tags:
- admin-quarantine
summary: Provider-triggered orphan Storage sweep
description: Deletes retry-window Storage orphans + discarded-quarantine payload
objects (Z-2), plus crash-window orphans in
outbound-xml/tdd-xml/receipts (RM-21). 207 if any per-object deletion
errored.
operationId: post_api_v1_admin_storage_gc_run
x-source: portal
x-service:
- api-internal
x-rbac: inbound_quarantine:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Per-bucket deletion counters
content:
application/json:
schema:
type: object
"207":
description: Partial — at least one per-object deletion errored (counters still
returned).
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/stripe/config:
get:
tags:
- billing
summary: Stripe connectivity check (Bearer, api-internal)
description: "Plan 212 S3: the api-internal Bearer re-implementation of the
portal checkStripeConnection action. Re-checks integrations:read on the
caller-Bearer client; pingStripe() is best-effort and never throws, so a
caller without the grant gets { reachable: false } (200), never a 5xx.
Served only by api-internal."
operationId: get_api_v1_admin_stripe_config
x-source: portal
x-service:
- api-internal
x-rbac: integrations:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: false
responses:
"200":
description: "{ reachable: boolean }"
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
post:
tags:
- billing
summary: Save the provider Stripe integration config (Bearer, api-internal)
description: 'Plan 212 S3: the api-internal Bearer re-implementation of the
portal saveStripeConfig action (Plan 198). Re-checks
integrations:read_write on the caller-Bearer client, then calls
admin_set_stripe_config on the service-role client with p_actor = the
VERIFIED Bearer claims.sub. WRITE-ONLY on the wire: secret fields are
only null (keep) / "__CLEAR__" (clear) / a fresh value (set) — never
echoed or logged; the result carries ONLY the curated non-secret
StripeIntegrationStatus. Served only by api-internal; the portal action
file was removed at Plan 213 S2 — the browser now reaches this route
through the portal server-side write-proxy (POST
/api/_proxy/admin/stripe/config).'
operationId: post_api_v1_admin_stripe_config
x-source: portal
x-service:
- api-internal
x-rbac: integrations:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: false
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminStripeConfigRequest"
responses:
"200":
description: "{ ok: true, status: StripeIntegrationStatus } | { ok: false, error
}"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/subscription-types/stripe-link:
post:
tags:
- admin-users
summary: Save a subscription package with a non-bypassable Stripe price
drift-guard (Bearer, api-internal)
description: "Plan 212 S3: the api-internal Bearer re-implementation of the
portal saveSubscriptionTypeStripeLink action (Plan 201). Re-checks
subscription_type:read_write on the caller-Bearer client; when a
price_id is linked it VERIFIES the Stripe Price against the portal
price/currency/interval + product id and a sibling duplicate-price_id —
ANY drift hard-blocks the write (409 drift, the
admin_update_subscription_type RPC never runs). Only a clean verify
saves via the caller client (DB-side RBAC + audit actor unchanged).
Served only by api-internal; the portal action file was removed at Plan
213 S2 — the browser now reaches this route through the portal
server-side write-proxy (POST
/api/_proxy/admin/subscription-types/stripe-link)."
operationId: post_api_v1_admin_subscription_types_stripe_link
x-source: portal
x-service:
- api-internal
x-rbac: subscription_type:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: false
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminSubscriptionTypesStripeLinkRequest"
responses:
"200":
description: "{ status: 'ok' } | drift | stripe_disabled | stripe_error |
rpc_error | forbidden"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"409":
description: drift — the linked Stripe Price is inconsistent with the portal
package (non-bypassable) — or stripe_disabled (the Stripe
integration is off, so the price is unverifiable).
content:
application/json:
schema: *a1
"502":
description: stripe_error — the Stripe `prices.retrieve` call failed.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/tenants/{id}/invoice-archive-mode:
post:
tags:
- admin-retention-dsar
summary: Set a tenant's invoice-XML archiving mode
description: "Turns the contractual keep-a-copy service on or off for ONE
customer tenant. It does NOT shorten anybody’s statutory retention — the
10-year duty under § 76 / § 85o ods. 15 zákona 222/2004 Z. z. stays with
the taxpayer — and it is NOT retroactive: the mode is frozen per
document at custody, so a change affects only documents received
afterwards. A contract reference and a reason are mandatory; refused
while the tenant is under a legal hold."
operationId: post_api_v1_admin_tenants_id_invoice_archive_mode
x-source: portal
x-service:
- api-internal
x-rbac: retention:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminTenantsIdInvoiceArchiveModeRequest"
responses:
"200":
description: The mode that is now in force
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/tenants/{id}/pseudonymize:
post:
tags:
- admin-retention-dsar
summary: Pseudonymize a closed customer tenant
description: Then scrub the GoTrue identity per user. RPC-first ordering
(re-runnable). 409 deferred_legal_hold; 409 not_closed; 403; 404.
operationId: post_api_v1_admin_tenants_id_pseudonymize
x-source: portal
x-service:
- api-internal
x-rbac: tenant:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: Pseudonymization summary + per-user (PII-free) scrub outcomes
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: deferred_legal_hold, or the tenant is not in the closed state.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/users/{id}/reset-mfa:
post:
tags:
- admin-users
summary: Admin 2FA reset (recovery for the F1 lockout)
description: Distinct from account closure. Authorizes + audits + clears the
target's app.account_mfa_lockout before deleting every factor via the
service-role Auth Admin API; the affected user is emailed. Missing
target -> 404; self-reset denied (403). Returns no session material.
operationId: post_api_v1_admin_users_id_reset_mfa
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: void (all MFA factors deleted, target re-enters mandatory enrollment)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/users/{id}/reset-password:
post:
tags:
- admin-users
summary: Provider sets another user's password via service role
description: AAL2; cannot self-reset. Audit recorded after the reset
(non-reversible mutation, P-021 §7).
operationId: post_api_v1_admin_users_id_reset_password
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminUsersIdResetPasswordRequest"
responses:
"200":
description: void (password reset)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/users/{id}/status:
post:
tags:
- admin-users
summary: Change user status + reconcile the GoTrue session (Plan 169 M8)
description: "Calls admin_set_user_status first, then bans the GoTrue session on
suspend/disable (so suspension is immediate independent of the RBAC
perm-cache TTL) or unbans it on reactivate. AAL2; self-status-change
denied (403); missing target -> 404. C4: unban never lifts account
closure's permanent ban — a closure tombstone identity is refused
(account_closed, 409). Denylisted for caching (GoTrue effect)."
operationId: post_api_v1_admin_users_id_status
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminUsersIdStatusRequest"
responses:
"200":
description: void (status changed; GoTrue session banned/unbanned)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/users/invite:
post:
tags:
- admin-users
summary: GoTrue invite-by-email + provision
description: Requires AAL2 + service role (server-only). There is no public
registration.
operationId: post_api_v1_admin_users_invite
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminUsersInviteRequest"
responses:
"200":
description: "{ userId: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/validation-rules/versions:
post:
tags:
- validation-rules
summary: Multipart upload of one compiled-Schematron XSLT + metadata
description: "For an upload-managed rule (release-managed rejected). Guards: ext
.xsl/.xslt only, size cap, XXE-safe parse + XSLT root, reject
xsl:include/import/import-schema, rule-id markers, duplicate-content.
Compiles via xslt3 to SEF, stores both byte-streams, creates a pending
version."
operationId: post_api_v1_admin_validation_rules_versions
x-source: portal
x-service:
- api-internal
x-rbac: validation_rules:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminValidationRulesVersionsRequest"
responses:
"202":
description: "{ versionId: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/validation-rules/versions/{id}/file:
get:
tags:
- validation-rules
summary: Verification download of a version's uploaded XSLT of record
description: Short-lived signed URL; release-managed version (no storage_path) -> 409.
operationId: get_api_v1_admin_validation_rules_versions_id_file
x-source: portal
x-service:
- portal
x-rbac: validation_rules:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ url: string } — short-lived signed Storage URL"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/workers:
get:
tags:
- workers
summary: Worker fleet dashboard — every heartbeat row (instance + kind pool view)
description: "ops.worker_heartbeat via worker_fleet_status:
instance/host/pid/incarnation/started_at/last_beat_at/draining_at/stats
+ computed beat_age_s. staleThresholdS (worker_heartbeat_stale_s,
resolved app-side) is returned so the UI/pool aggregates classify live
vs stale without a second round-trip."
operationId: get_api_v1_admin_workers
x-source: portal
x-service:
- portal
x-rbac: worker_ops:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: "{ instances: WorkerInstance[], staleThresholdS: number }"
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/workers/commands:
get:
tags:
- workers
summary: Recent cooperative-restart commands + derived status + ack rollup
description: worker_command_list — derived status
(pending/completed/cancelled/expired, never a mutable enum) + acked
instances/timestamps.
operationId: get_api_v1_admin_workers_commands
x-source: portal
x-service:
- portal
x-rbac: worker_ops:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
parameters:
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 200
responses:
"200":
description: "{ commands: WorkerCommand[] }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/workers/commands/{id}/cancel:
post:
tags:
- workers
summary: Cancel a still-pending cooperative-restart command
description: Stops the REMAINING rollout only — instances that already acked
have already drained. worker_command_cancel; P0002 (not pending) -> 404.
operationId: post_api_v1_admin_workers_commands_id_cancel
x-source: portal
x-service:
- api-internal
x-rbac: worker_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ ok: true }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_pending — already completed/cancelled/expired, or an unknown id.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/workers/dump:
get:
tags:
- workers
summary: DB-state JSON dump of the worker fleet (download)
description: "Route-composed: fleet status + queue stats + a peek of all four
queues + command history + the resolved worker_heartbeat_stale_s
threshold. DB-state only, NEVER process memory. Each embedded peek is
already self-audited by worker_queue_peek; this route additionally
writes ONE worker_ops.dump row (log_worker_dump, row counts only) BEFORE
serving."
operationId: get_api_v1_admin_workers_dump
x-source: portal
x-service:
- portal
x-rbac: worker_ops:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: application/json attachment — worker-fleet-dump-<ts>.json
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"503":
description: audit_failed — the log_worker_dump audit row did not land; no data
served.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/workers/queues:
get:
tags:
- workers
summary: Depth + oldest-message age for the four pgmq queues
description: worker_queue_stats —
invoice_validation_q/invoice_send_q/mls_send_q/tdd_send_q, hardcoded IN
the RPC (never caller-supplied). DLQ detail stays on /configuration/dlq.
operationId: get_api_v1_admin_workers_queues
x-source: portal
x-service:
- portal
x-rbac: worker_ops:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: "{ queues: { queueName, depth, oldestAgeS }[] }"
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/workers/queues/{queue}/peek:
get:
tags:
- workers
summary: Non-claiming, redacted peek of a pgmq queue (up to 50 messages)
description: worker_queue_peek reads pgmq.q_<name> directly (never pgmq.read —
that bumps vt). {queue} is validated against the pinned four-name
whitelist INSIDE the RPC; unknown name -> 22023 -> 400. Messages carry
cross-tenant document ids (never invoice content) — a sensitive read, so
the RPC writes its own audit row BEFORE returning.
operationId: get_api_v1_admin_workers_queues_queue_peek
x-source: portal
x-service:
- portal
x-rbac: worker_ops:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: queue
in: path
required: true
schema:
type: string
- name: limit
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 50
responses:
"200":
description: "{ messages: { msgId, readCt, enqueuedAt, vt, message }[] }"
content:
application/json:
schema:
type: object
"400":
description: unknown_queue — {queue} is not one of the four whitelisted names.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/admin/workers/restart:
post:
tags:
- workers
summary: Request a cooperative restart — per instance or rolling per kind
description: Consumed by the target worker on its own worker_beat_poll
round-trip and honored via its existing graceful drain + the
restart:unless-stopped supervisor relaunch. NEVER a container kill.
instanceId present = targeted; absent = kind-wide rolling.
WORKER_RESTART_SPACING_S (env, default 90) is resolved by this route and
stamped onto the command row.
operationId: post_api_v1_admin_workers_restart
x-source: portal
x-service:
- api-internal
x-rbac: worker_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AdminWorkersRestartRequest"
responses:
"201":
description: "{ commandId: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: unknown_instance — a targeted instanceId with no live heartbeat row
of that kind.
content:
application/json:
schema: *a1
"409":
description: restart_already_pending — a pending command already exists for this
kind/target, or the targeted<->kind-wide cross-refuse (§5.5).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/agent/inbound:
get:
tags:
- agent-m2m
summary: Lease the next delivery_pending outbox document for the agent's tenant
description: FOR UPDATE SKIP LOCKED + issue a hashed single-use ack_token. 204
on an empty outbox.
operationId: get_api_v1_agent_inbound
x-source: portal
x-service:
- portal
x-rbac: agent-auth
x-scope: tenant
x-audited: true
x-auth-kind: agent-auth
x-try-it-out: false
responses:
"200":
description: A document was leased (an ack_token is issued for the follow-up ack).
content:
application/json:
schema:
type: object
"204":
description: 200 with the leased document, or 204 (empty outbox)
"401":
description: missing/invalid agent credential (api-key or mTLS).
content:
application/json:
schema: *a1
"403":
description: forbidden — untrusted proxy provenance, or a token replayed across
tenants (N12).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- agentAuth: []
/api/v1/agent/inbound/{id}/ack:
post:
tags:
- agent-m2m
summary: Acknowledge a leased delivery
description: Hashed single-use ack_token match + tenant re-check (N12, a stolen
token from another tenant -> 403); transitions to acked.
operationId: post_api_v1_agent_inbound_id_ack
x-source: portal
x-service:
- portal
x-rbac: agent-auth
x-scope: tenant
x-audited: true
x-auth-kind: agent-auth
x-try-it-out: false
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AgentInboundIdAckRequest"
responses:
"200":
description: void (delivery acknowledged)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: missing/invalid agent credential (api-key or mTLS).
content:
application/json:
schema: *a1
"403":
description: forbidden — untrusted proxy provenance, or a token replayed across
tenants (N12).
content:
application/json:
schema: *a1
"404":
description: not_found.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- agentAuth: []
/api/v1/agent/outbound:
post:
tags:
- agent-m2m
summary: M2M invoice ingest
description: Ingest-idempotency-key replay (safe network retries, V3) -> the
same extracted validation-storage sequence as the browser upload via
agent-variant RPCs. 429 backpressure over pipeline_q_depth().
operationId: post_api_v1_agent_outbound
x-source: portal
x-service:
- portal
x-rbac: agent-auth
x-scope: tenant
x-audited: true
x-auth-kind: agent-auth
x-try-it-out: false
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
- name: Idempotency-Key
in: header
required: false
schema:
type: string
description: Ingest-idempotency key for safe network retries (V3). Also accepted
as `X-Idempotency-Key`; a replay returns the original 202 {
documentId }.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1AgentOutboundRequest"
responses:
"202":
description: Accepted (or an idempotent replay of an earlier ingest).
content:
application/json:
schema:
type: object
properties:
documentId:
type: string
format: uuid
required:
- documentId
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: missing/invalid agent credential (api-key or mTLS).
content:
application/json:
schema: *a1
"403":
description: forbidden — untrusted proxy provenance, or a token replayed across
tenants (N12).
content:
application/json:
schema: *a1
"429":
description: backpressure over pipeline_q_depth().
content:
application/json:
schema: *a1
"503":
description: idempotency_lookup_failed / transient store failure (fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- agentAuth: []
/api/v1/audit/search:
get:
tags:
- audit
summary: Provider cross-document audit-log search
description: target_id without target_type -> 400 (composite index). Paginated
(page, pageSize ∈ {25,50,100}). 429 on rate-limit.
operationId: get_api_v1_audit_search
x-source: portal
x-service:
- portal
x-rbac: audit_log:read + provider (audit_log_detail:read gates before/after)
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: action
in: query
required: false
schema:
type: string
- name: target_type
in: query
required: false
schema:
type: string
- name: target_id
in: query
required: false
schema:
type: string
- name: actor
in: query
required: false
schema:
type: string
- name: tenant
in: query
required: false
schema:
type: string
- name: from
in: query
required: false
schema:
type: string
- name: to
in: query
required: false
schema:
type: string
- name: outcome
in: query
required: false
schema:
type: string
- name: page
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 9007199254740991
- name: pageSize
in: query
required: false
schema:
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
responses:
"200":
description: Paginated audit_log search results
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/audit/search/export:
get:
tags:
- audit
summary: CSV export of the same audit search
description: Same filters as /audit/search. before/after columns present only
with audit_log_detail:read. Rows capped at 10 000; a cap hit is logged.
operationId: get_api_v1_audit_search_export
x-source: portal
x-service:
- portal
x-rbac: audit_log:read + provider (audit_log_detail:read adds before/after CSV
columns)
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: action
in: query
required: false
schema:
type: string
- name: target_type
in: query
required: false
schema:
type: string
- name: target_id
in: query
required: false
schema:
type: string
- name: actor
in: query
required: false
schema:
type: string
- name: tenant
in: query
required: false
schema:
type: string
- name: from
in: query
required: false
schema:
type: string
- name: to
in: query
required: false
schema:
type: string
- name: outcome
in: query
required: false
schema:
type: string
responses:
"200":
description: text/csv attachment
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/billing/change-package:
post:
tags:
- billing
summary: Change the tenant’s package (prorated, SCA-aware, atomic)
description: "Plan 196: fail-closed & atomic w.r.t. Stripe. Rejects a
non-billable/inactive package (409 package_not_billable) and a customer
with no default PM (409 no_payment_method). Creates-or-updates the
Stripe subscription with `proration_behavior:create_prorations` under a
deterministic idempotency key (double-submit → one mutation). SCA: an
`incomplete` result returns `{ requiresAction:true, clientSecret }` and
does NOT change the pointer. Only a confirmed active/trialing
subscription flips `tenant.subscription_type_id` via the
service_role-only `org_change_subscription_type` RPC; a Stripe failure
leaves both Stripe and the pointer unchanged. Audited
(billing.package_changed, before/after package)."
operationId: post_api_v1_billing_change_package
x-source: portal
x-service:
- api-internal
x-rbac: billing:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1BillingChangePackageRequest"
responses:
"200":
description: "{ ok: true, status } | { requiresAction: true, clientSecret }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"409":
description: package_not_billable (inactive / no stripe_price_id),
no_payment_method, or change_package_incomplete.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/billing/confirm-setup:
post:
tags:
- billing
summary: Promote the captured card to the customer’s default (charged) PM
description: "Plan 196: retrieves the confirmed SetupIntent, verifies it belongs
to THIS tenant’s customer (anti cross-customer → 403), reads its
payment_method and sets `invoice_settings.default_payment_method` — so
the saved card is the one actually CHARGED (the webhook syncs the
brand/last4 display separately). No PAN handled. Audited
(billing.payment_method_default_set)."
operationId: post_api_v1_billing_confirm_setup
x-source: portal
x-service:
- api-internal
x-rbac: billing:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1BillingConfirmSetupRequest"
responses:
"200":
description: "{ ok: true }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"409":
description: no_payment_method (the SetupIntent carries no payment method).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/billing/invoice/{id}/pdf:
get:
tags:
- billing
summary: Redirect to a FRESH Stripe subscription-invoice PDF url (own-tenant)
description: "Plan 196: loads billing_invoice by id with the RLS-bound session
client (own-tenant only; cross-tenant/unknown → 404 anti-leak), then
re-fetches a FRESH `invoice_pdf`/`hosted_invoice_url` from the Stripe
API (stored urls go stale) and 302-redirects to it. Audited
(billing.invoice_downloaded) — records the invoice id, NEVER the bearer
url; fail-closed BEFORE the redirect."
operationId: get_api_v1_billing_invoice_id_pdf
x-source: portal
x-service:
- portal
x-rbac: billing:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"302":
description: Redirect to the fresh Stripe bearer url.
content:
application/json:
schema: *a1
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown or cross-tenant invoice id (anti-leak).
content:
application/json:
schema: *a1
"409":
description: not_available — Stripe has no PDF/hosted url for the invoice yet.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/billing/setup-intent:
post:
tags:
- billing
summary: Create a Stripe SetupIntent for payment-method capture
description: "Plan 196: mints a SetupIntent (`usage:off_session`) so the browser
captures a card with Stripe Elements — card data posts DIRECTLY to
Stripe, never to our server. Ensures the tenant’s Stripe customer first
(idempotent). Returns `{ clientSecret }`. Audited
(billing.setup_intent_created); fail-closed on the audit (503)."
operationId: post_api_v1_billing_setup_intent
x-source: portal
x-service:
- api-internal
x-rbac: billing:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: "{ clientSecret: string | null }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"503":
description: billing_disabled (Stripe integration off) or audit_failed.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/evidence:
get:
tags:
- evidence
summary: Paginated browse over the unified evidence_record ledger
description: Both directions, incl. received MLS (evidence_type=mls) and TDD
receipts (direction=tdd). Rate-limited (bucket evidence_list).
operationId: get_api_v1_evidence
x-source: portal
x-service:
- api-internal
x-rbac: "at least one of outbound_document / inbound_document /
inbound_quarantine / tdd_document : read"
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: direction
in: query
required: false
schema:
type: string
- name: type
in: query
required: false
schema:
type: string
- name: from
in: query
required: false
schema:
type: string
- name: to
in: query
required: false
schema:
type: string
- name: outboundDocumentId
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: inboundDocumentId
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: tddDocumentId
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: page
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 9007199254740991
responses:
"200":
description: Paginated list of evidence_record rows
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"429":
description: rate_limited (bucket evidence_list).
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"503":
description: rate_limit_failed — the limiter RPC failed (fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/evidence/{id}/download:
get:
tags:
- evidence
summary: Short-lived signed URL for the evidence object
description: 5-minute signed URL in the receipts bucket. A zero-owner mls object
is provider-only at the Storage layer even when the ledger row is
tenant-visible. Rate-limited (bucket evidence_download).
operationId: get_api_v1_evidence_id_download
x-source: portal
x-service:
- portal
x-rbac: same row-level RLS as the list (no extra route-level gate)
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ url: string } — 5-minute signed Storage URL"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"429":
description: rate_limited (bucket evidence_download).
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"503":
description: rate_limit_failed — the limiter RPC failed (fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/health:
get:
tags:
- health
summary: Liveness + readiness probe (DB, api-internal pair, schema)
description: "Three checks, all required for a 200: db — a cheap select-1-style
ping against the non-tenant system_setting table via the service-role
client (no tenant/PII read); apiInternal + contract — the
portal-web↔api-internal version-locked-pair probe of _meta (Plan 217);
schema — the code↔schema skew guard comparing the live migration ledger
against this build (Plan 224). Body is only {status, checks:{db,
apiInternal, contract, schema}} — never DB error text, secrets, env,
contract/build versions, migration versions, git SHA, or hostname."
operationId: get_api_v1_health
x-source: portal
x-service:
- api-internal
- api-public
- portal
x-rbac: public
x-scope: n/a
x-audited: false
x-auth-kind: public
x-try-it-out: true
responses:
"200":
description: '{ status: "ok" | "down", checks: { db: boolean, apiInternal:
boolean, contract: boolean, schema: boolean } } (503 when down)'
content:
application/json:
schema:
type: object
"503":
description: down — one or more of the four checks failed.
content:
application/json:
schema:
type: object
default:
$ref: "#/components/responses/ApiError"
security: []
/api/v1/inbound:
get:
tags:
- inbound
summary: Paginated tenant-scoped list of received invoices
description: Filters state, date_from, date_to, page; projection includes
mls_status. Rate-limited (bucket inbound_list) -> 429 on exceed.
operationId: get_api_v1_inbound
x-source: portal
x-service:
- api-internal
x-rbac: inbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: state
in: query
required: false
schema:
type: string
- name: date_from
in: query
required: false
schema:
type: string
- name: date_to
in: query
required: false
schema:
type: string
- name: page
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 9007199254740991
responses:
"200":
description: Paginated list of inbound_document rows
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"429":
description: rate_limited (bucket inbound_list).
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"503":
description: rate_limit_failed — the limiter RPC failed (fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/inbound/{id}:
get:
tags:
- inbound
summary: Tenant received-invoice detail
description: RLS-scoped resolve before any audit call (unknown-id and
foreign-tenant-id both 404). Response = the document row + delivery
(delivery_record) + evidence (sha256/size only, never raw bytes).
Response gains a permission-gated tdd block when the caller holds
tdd_document:read.
operationId: get_api_v1_inbound_id
x-source: portal
x-service:
- api-internal
x-rbac: inbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: inbound_document row + delivery + evidence (+ optional tdd block)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/inbound/{id}/attachments-zip:
get:
tags:
- inbound
summary: All embedded attachments as one ZIP
description: "The 1:1 inbound twin of the outbound …/attachments-zip (Plan 176).
Every embedded attachment of the received invoice, packed into one ZIP —
the attachments alone, unlike /bundle which also packs the source XML
and the TDD XML. Serves EVERY attachment, not only the application/pdf
the per-index route allows: that route hands the browser bytes under a
Content-Type it renders, whereas a ZIP is inert. Non-PDF entries get a
.bin extension. 404 when the invoice carries no embedded attachment; 409
when nothing is stored yet."
operationId: get_api_v1_inbound_id_attachments_zip
x-source: portal
x-service:
- portal
x-rbac: inbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: application/zip of the attachments
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/inbound/{id}/attachments/{index}:
get:
tags:
- inbound
summary: Decoded embedded attachment bytes
description: The 1:1 inbound twin of the outbound per-index attachment route
(Plan 173). Returns the decoded embedded attachment (PDF) bytes at the
given index; 415 for a non-PDF MIME, 404 for an out-of-range index.
operationId: get_api_v1_inbound_id_attachments_index
x-source: portal
x-service:
- portal
x-rbac: inbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: index
in: path
required: true
schema:
type: string
responses:
"200":
description: application/pdf attachment bytes
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/inbound/{id}/bundle:
get:
tags:
- inbound
summary: ZIP bundle (XML + TDD + attachments + PDF)
description: The 1:1 inbound twin of the outbound …/bundle (Plan 173). One ZIP
holding the received source UBL XML, the C3-side SK TDD XML
(opportunistic — inbound_document_id + reporter_role=C3, omitted without
tdd_document:read), every embedded attachment, and the A4 PDF
visualization (BEST EFFORT — a render failure never takes the archive
down). PDF labels use `?locale=` (sk|en, default sk). 409 when nothing
is stored yet.
operationId: get_api_v1_inbound_id_bundle
x-source: portal
x-service:
- portal
x-rbac: inbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: application/zip bundle
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/inbound/{id}/download:
get:
tags:
- inbound
summary: Signed URL for a received invoice's stored XML
description: 5-minute signed URL, RLS-bound to the caller's tenant prefix.
Rate-limited (bucket inbound_download) -> 429 on exceed.
operationId: get_api_v1_inbound_id_download
x-source: portal
x-service:
- portal
x-rbac: inbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ url: string } — 5-minute signed Storage URL"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"429":
description: rate_limited (bucket inbound_download).
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"503":
description: rate_limit_failed — the limiter RPC failed (fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/inbound/{id}/pdf:
get:
tags:
- inbound
summary: A4 PDF visualization of the received invoice
description: The 1:1 inbound twin of the outbound …/pdf (Plan 173). A
server-rendered, read-only A4 visualization of the received UBL — NOT
the invoice; every page carries the notice that the XML is the legally
binding original. The header/parties/dates/totals are extracted from the
single parse (inbound_document lacks the parsed columns the outbound row
carries). Renders in the locale the caller states via `?locale=` (sk|en,
default sk); `?disposition=inline` renders in a new tab. Rate-limited
under the `inbound_pdf` bucket. 409 when nothing is stored yet; 422 when
the stored payload does not parse.
operationId: get_api_v1_inbound_id_pdf
x-source: portal
x-service:
- portal
x-rbac: inbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: application/pdf — the A4 visualization
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: not_available — the reception has no stored file yet.
content:
application/json:
schema: *a1
"422":
description: parse_failed — the stored payload is not parsable XML.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/inbound/{id}/receipts-zip:
get:
tags:
- inbound
summary: All receipts as one ZIP
description: "The 1:1 inbound twin of the outbound …/receipts-zip (Plan 173).
Every proof about this received invoice packed into one ZIP: the
reception's AS4 receipt and MLS (evidence_record where
inbound_document_id={id}), plus the C3 TDD's AS4 receipt
(opportunistic). The Potvrdenka tab's 'download all'. Audit is
fail-closed and PER OBJECT (log_evidence_download once per row). 404
when no receipt has been stored yet."
operationId: get_api_v1_inbound_id_receipts_zip
x-source: portal
x-service:
- portal
x-rbac: inbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: application/zip of the receipts
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/inbound/{id}/tdd/download:
get:
tags:
- inbound
summary: Signed URL for the C3-side received-invoice TDD XML
description: The inbound mirror of the outbound …/tdd/download row; RLS-bound
client signs the stored tdd-xml path.
operationId: get_api_v1_inbound_id_tdd_download
x-source: portal
x-service:
- portal
x-rbac: inbound_document:read ∧ tdd_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ url: string } — 5-minute signed Storage URL"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/inbound/export:
get:
tags:
- inbound
summary: CSV export of the received-invoices list
description: "CSV export honoring the same filters as the received-invoices list
page (state, company, q free-text search over
invoice_number/seller_name/transmission_id/sender_participant_id,
date_from/date_to received-date range, validation →
content_validation_status, tdd → tdd_reporting_required, amount range)
via the shared buildInboundListQuery. Columns mirror the table
(received/company/invoice
no./supplier/amount/currency/TDD/validation/state; Actions excluded;
Company only for providers). Export is selected-rows-only via ?ids=
(comma-joined UUIDs). ?locale= (sk|en, default sk) for CSV labels.
Rate-limited (bucket inbound_export); capped at 10 000 rows.
Audit-before-bytes: the exported row count is recorded before any CSV is
emitted."
operationId: get_api_v1_inbound_export
x-source: portal
x-service:
- portal
x-rbac: inbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: state
in: query
required: false
schema:
type: string
- name: company
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: q
in: query
required: false
schema:
type: string
- name: date_from
in: query
required: false
schema:
type: string
- name: date_to
in: query
required: false
schema:
type: string
- name: validation
in: query
required: false
schema:
type: string
enum:
- passed
- failed
- name: tdd
in: query
required: false
schema:
type: string
enum:
- required
- not_required
- name: amount
in: query
required: false
schema:
type: string
- name: ids
in: query
required: false
schema:
type: string
- name: locale
in: query
required: false
schema:
type: string
enum:
- sk
- en
responses:
"200":
description: text/csv attachment (received-invoices.csv)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"429":
description: rate_limited (bucket inbound_export).
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"503":
description: rate_limit_failed / audit_failed (fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/integration/participants/check:
get:
tags:
- participants
summary: Plan 207 — public integration-key SMP/SML capability check (single)
description: Integration-key auth (verifyIntegrationKey; NOT a session, NOT
verifyAgent). Requires the lookup:single scope (403 otherwise),
rate-limited per KEY (not per IP), input validated to the Adapter's own
rules, doctype defaulted to PEPPOL BIS Billing 3.0 when omitted,
fail-closed audit before the answer. ADVISORY — never a send gate.
Tri-state result registered | not_registered | unknown; not_registered
is a 200. Returns NO tenant-scoped data (invariant §5.6.1). format=text
returns a flat key=value body for VFP.
operationId: get_api_v1_integration_participants_check
x-source: portal
x-service:
- api-internal
- api-public
- portal
x-rbac: integration-key (lookup:single scope)
x-scope: tenant
x-audited: true
x-auth-kind: integration-key-auth
x-try-it-out: false
parameters:
- name: participantId
in: query
required: true
schema:
type: string
- name: documentTypeId
in: query
required: false
schema:
type: string
- name: format
in: query
required: false
schema:
type: string
enum:
- json
- text
responses:
"200":
description: "{ participantId, result: 'registered' | 'not_registered' |
'unknown', checkedAt }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: "missing/invalid integration credential — no `Authorization: Bearer
<key>` / `X-Integration-Key` header, or an unknown/revoked key
(uniform, no distinction)."
content:
application/json:
schema: *a1
"403":
description: insufficient_scope — the key lacks lookup:single.
content:
application/json:
schema: *a1
"429":
description: rate_limited (per-key bucket integration_lookup_single).
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"502":
description: lookup_failed — an upstream SMP/SML fault (never a send gate).
content:
application/json:
schema: *a1
"503":
description: audit_failed / rate_limit_failed — a support RPC failed
(fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- integrationKeyAuth: []
/api/v1/integration/participants/check-batch:
post:
tags:
- participants
summary: Plan 207 — public integration-key SMP/SML capability check (bulk)
description: "Integration-key auth (verifyIntegrationKey; NOT a session, NOT
verifyAgent). Requires the lookup:bulk scope (403 otherwise),
rate-limited per KEY on a separate, tighter bucket, batch-capped (400
above integration_lookup_batch_max), input validated to the Adapter's
own rules, doctype defaulted to PEPPOL BIS Billing 3.0 when omitted.
Fail-closed: ONE audit row per batch (ids + outcome counts) before the
answer. ADVISORY — never a send gate. Per-participant results are
INDEPENDENT: one unknown never fails the batch. Returns NO tenant-scoped
data (invariant §5.6.1). format=text returns flat
`<participantId>=<result>` lines for VFP."
operationId: post_api_v1_integration_participants_check_batch
x-source: portal
x-service:
- api-internal
- api-public
- portal
x-rbac: integration-key (lookup:bulk scope)
x-scope: tenant
x-audited: true
x-auth-kind: integration-key-auth
x-try-it-out: false
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1IntegrationParticipantsCheckBatchRequest"
responses:
"200":
description: "{ results: { participantId, result: 'registered' |
'not_registered' | 'unknown' }[], counts, checkedAt }"
content:
application/json:
schema:
type: object
"400":
description: invalid_body / participants_required / batch_too_large /
invalid_participant_id / invalid_document_type_id.
content:
application/json:
schema: *a1
"401":
description: "missing/invalid integration credential — no `Authorization: Bearer
<key>` / `X-Integration-Key` header, or an unknown/revoked key
(uniform, no distinction)."
content:
application/json:
schema: *a1
"403":
description: insufficient_scope — the key lacks lookup:bulk.
content:
application/json:
schema: *a1
"429":
description: rate_limited (per-key bucket integration_lookup_bulk).
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"503":
description: audit_failed / rate_limit_failed — a support RPC failed
(fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- integrationKeyAuth: []
/api/v1/internal/billing-recon/run:
post:
tags:
- billing
summary: Internal billing-reconciliation sweep trigger (service-to-service,
shared-secret)
description: "Plan 199: the pg_cron→pg_net-invoked internal trigger for the
detect-and-report reconciliation sweep over the portal’s OWN billing
mirror (NOT eFaktura). NOT a user surface — NO session/RBAC.
Authenticated ONLY by a constant-time `Authorization: Bearer
<BILLING_RECON_INTERNAL_SECRET>` compare (any miss → 401 no body +
authz_403 security-event). Fail-closed: an UNSET secret → 503 (dormant);
secret OK but BILLING_RECON_ENABLED≠true or Stripe disabled → 200
{skipped} with no Stripe call. Otherwise it claims a run
(billing_recon_claim_run), diffs Stripe vs
tenant_billing/billing_invoice/tenant.subscription_type_id, stamps
ops.billing_recon_run, and emits ONE billing_drift security-event on
drift — never mutating billing state (the Plan 195 webhook stays the
sole writer). The secret is never logged, returned, or audited in
cleartext."
operationId: post_api_v1_internal_billing_recon_run
x-source: portal
x-service:
- api-internal
x-rbac: service-auth
x-scope: platform
x-audited: true
x-auth-kind: service-auth
x-try-it-out: false
parameters:
- name: X-Timestamp
in: header
required: true
schema:
type: string
description: Epoch-seconds timestamp folded into the signed HMAC canonical
string; ±300s replay window (webhook-hmac.ts). Paired with the
`X-Signature` HMAC — see `security`.
responses:
"200":
description: "{ ran, runId, status } | { skipped } (200); 401 (bad bearer) | 503
(unconfigured)"
content:
application/json:
schema:
type: object
"400":
description: invalid_* — malformed body or missing signature headers.
content:
application/json:
schema: *a1
"401":
description: Missing/incorrect bearer — no body; an authz_403 security-event is
recorded.
content:
application/json:
schema: *a1
"503":
description: billing_recon_unconfigured — BILLING_RECON_INTERNAL_SECRET unset
(dormant).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- hmacSignature: []
/api/v1/internal/bottleneck-check/run:
post:
tags:
- workers
summary: Internal bottleneck-check trigger (service-to-service, shared-secret)
description: "Plan 264: the pg_cron→pg_net-invoked trigger for the half-hourly
bottleneck sweep. NOT a user surface — no session, no RBAC, body
ignored; authenticated ONLY by a constant-time `Authorization: Bearer
<BOTTLENECK_CHECK_INTERNAL_SECRET>` compare (any miss → 401 no body +
authz_403). Fail-closed: an unset or under-32-char secret → 503
(dormant, indistinguishable); secret OK but
BOTTLENECK_CHECK_ENABLED≠true → 200 {skipped} with no Adapter call. On a
non-`none` verdict it emits one ERROR log record (the OneUptime alerting
substrate) and opens a deduped incident (source=bottleneck,
source_key=verdict); it notifies provider admins only on a verdict EDGE,
because notification also means email."
operationId: post_api_v1_internal_bottleneck_check_run
x-source: portal
x-service:
- api-internal
x-rbac: service-auth
x-scope: platform
x-audited: true
x-auth-kind: service-auth
x-try-it-out: false
parameters:
- name: X-Timestamp
in: header
required: true
schema:
type: string
description: Epoch-seconds timestamp folded into the signed HMAC canonical
string; ±300s replay window (webhook-hmac.ts). Paired with the
`X-Signature` HMAC — see `security`.
responses:
"200":
description: "{ ran, runId, status, verdict? } | { skipped } (200)"
content:
application/json:
schema:
type: object
"400":
description: invalid_* — malformed body or missing signature headers.
content:
application/json:
schema: *a1
"401":
description: Missing/incorrect bearer — no body; an authz_403 security-event is
recorded.
content:
application/json:
schema: *a1
"503":
description: bottleneck_check_unconfigured — the internal secret is unset or too
short (dormant).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- hmacSignature: []
/api/v1/invoices/outbound:
get:
tags:
- invoices-outbound
summary: Paginated list of outbound documents
description: "Filters: state, document_type, date_from, date_to, page."
operationId: get_api_v1_invoices_outbound
x-source: portal
x-service:
- api-internal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: state
in: query
required: false
schema:
type: string
- name: document_type
in: query
required: false
schema:
type: string
- name: date_from
in: query
required: false
schema:
type: string
- name: date_to
in: query
required: false
schema:
type: string
- name: page
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 9007199254740991
responses:
"200":
description: Paginated list of outbound_document rows
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
post:
tags:
- invoices-outbound
summary: Accept one eFaktúra XML for validation + send
description: Sync steps 1-3, insert outbound_document (state=received),
atomically enqueue the validation job onto the durable pgmq queue; a
separate worker drains it. 429 backpressure when the queue is deep; 403
account_inactive for a suspended/closed client.
operationId: post_api_v1_invoices_outbound
x-source: portal
x-service:
- api-internal
x-rbac: outbound_document:read_write + account-active (FR-11)
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- multipart/form-data
description: multipart/form-data carrying a single `file` field (the eFaktúra
XML).
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1InvoicesOutboundRequest"
responses:
"202":
description: Accepted; the validation job is enqueued.
content:
application/json:
schema:
type: object
properties:
documentId:
type: string
format: uuid
required:
- documentId
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"409":
description: "duplicate_document — identical content already ingested (body:
existingDocumentId)."
content:
application/json:
schema:
type: object
properties:
error:
type: string
existingDocumentId:
type: string
"429":
description: backpressure — the validation queue is saturated; retry shortly.
content:
application/json:
schema: *a1
"503":
description: A sync ingest/storage failure (fail-closed; no orphaned rows or
files).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}:
get:
tags:
- invoices-outbound
summary: Single outbound document + validation results
description: RLS enforces tenant scope. Includes the P-031 PEPPOL routing
identifiers (sender_participant_id, customization_id, process_id,
document_type_id).
operationId: get_api_v1_invoices_outbound_id
x-source: portal
x-service:
- api-internal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: The outbound_document row + validation results
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
patch:
tags:
- invoices-outbound
summary: Revalidate an errored/received document
description: action=revalidate resets to received and re-enqueues the validation
job. 403 account_inactive for a suspended/closed client.
operationId: patch_api_v1_invoices_outbound_id
x-source: portal
x-service:
- api-internal
x-rbac: outbound_document:read_write + account-active (FR-11)
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PatchApiV1InvoicesOutboundIdRequest"
responses:
"200":
description: The updated outbound_document row
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/attachments-zip:
get:
tags:
- invoices-outbound
summary: All embedded attachments as one ZIP
description: "Every embedded attachment of the invoice, packed into one ZIP —
the attachments alone, unlike /bundle which also packs the source XML
and the TDD XML. Serves EVERY attachment, not only the application/pdf
the per-index route allows: that route hands the browser bytes under a
Content-Type it renders, whereas a ZIP is inert. Non-PDF entries get a
.bin extension. 404 when the invoice carries no embedded attachment; 409
when nothing is stored yet."
operationId: get_api_v1_invoices_outbound_id_attachments_zip
x-source: portal
x-service:
- portal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: application/zip of the attachments
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/attachments/{index}:
get:
tags:
- invoices-outbound
summary: Decoded embedded attachment bytes
description: Returns the decoded embedded attachment (PDF) bytes at the given index.
operationId: get_api_v1_invoices_outbound_id_attachments_index
x-source: portal
x-service:
- portal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: index
in: path
required: true
schema:
type: string
responses:
"200":
description: application/pdf attachment bytes
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/bundle:
get:
tags:
- invoices-outbound
summary: ZIP bundle (XML + attachments)
description: "One ZIP holding the source UBL XML, the TDD XML (opportunistic —
omitted without tdd_document:read), every embedded attachment, and the
A4 PDF visualization. The PDF is BEST EFFORT: if rendering fails the ZIP
still ships everything else, because a visualization must not take the
archive down. Its labels use the locale the caller states via `?locale=`
(sk|en, default sk) — this route has no [locale] segment, so the locale
cannot be inferred. 409 when nothing is stored yet."
operationId: get_api_v1_invoices_outbound_id_bundle
x-source: portal
x-service:
- portal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: application/zip bundle
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/download:
get:
tags:
- invoices-outbound
summary: Signed URL for the stored invoice XML
description: 5-minute signed URL; 409 if the file is not yet available.
operationId: get_api_v1_invoices_outbound_id_download
x-source: portal
x-service:
- portal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ url: string } — 5-minute signed Storage URL"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: not_ready — the stored invoice XML is not yet available.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/pdf:
get:
tags:
- invoices-outbound
summary: A4 PDF visualization of the invoice
description: "A server-rendered, read-only A4 visualization of the stored UBL
payload — NOT the invoice. The portal does not create invoices; every
page carries a notice stating the UBL XML is the legally binding
original. Renders in the locale the caller states via `?locale=` (sk|en,
default sk): an /api route has no [locale] segment, so the locale cannot
be inferred. 409 when nothing is stored yet; 422 when the stored payload
does not parse. Rate-limited under the `invoice_pdf` bucket — rendering
is CPU work and renders are serialized process-wide."
operationId: get_api_v1_invoices_outbound_id_pdf
x-source: portal
x-service:
- portal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: application/pdf — the A4 visualization
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: not_available — the document has no stored file yet.
content:
application/json:
schema: *a1
"422":
description: parse_failed — the stored payload is not parsable XML.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/receipts-zip:
get:
tags:
- invoices-outbound
summary: All receipts as one ZIP
description: "Every proof of delivery the network returned about this sent
invoice, packed into one ZIP: the invoice's own AS4 receipt and MLS,
plus the SK TDD's AS4 receipt (opportunistic — omitted without
tdd_document:read). The Receipts tab's 'download all', sibling to
/attachments-zip. Audit is fail-closed and PER OBJECT
(log_evidence_download once per row), so the trail records each evidence
object that left. 404 when no receipt has been stored yet."
operationId: get_api_v1_invoices_outbound_id_receipts_zip
x-source: portal
x-service:
- portal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: application/zip of the receipts
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/retry-send:
post:
tags:
- invoices-outbound
summary: RM-07 client retry-with-fresh-discovery
description: Valid only from send_rejected; mints a NEW
invoice_transmission_uuid, transitions to ready_for_peppol, re-enqueues.
409 invalid_state on the wrong source state; 404 not_found for a
missing/cross-tenant document (IDOR-safe); 403 account_inactive for a
suspended/closed client.
operationId: post_api_v1_invoices_outbound_id_retry_send
x-source: portal
x-service:
- api-internal
x-rbac: outbound_document:read_write + account-active (FR-11)
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"202":
description: Re-enqueued with a fresh invoice_transmission_uuid.
content:
application/json:
schema:
type: object
properties:
documentId:
type: string
format: uuid
required:
- documentId
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: invalid_state — retry-send is valid only from send_rejected.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/tdd/abandon:
post:
tags:
- invoices-outbound
summary: Abandon a stuck C2 SK TDD obligation (Plan 164)
description: The explicit admin "this issued reportable invoice never
transmitted and we are NOT reporting it to FS SR" decision for an
awaiting C2 obligation. Required JSON { reason } (1..500). 400
reason_required; 409 invalid_state if the parent already transmitted
(must generate); 404 for a missing/cross-tenant document (IDOR-safe);
403 account_inactive/forbidden.
operationId: post_api_v1_invoices_outbound_id_tdd_abandon
x-source: portal
x-service:
- api-internal
x-rbac: tdd_document:read_write + tenant-scope + account-active (FR-11)
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1InvoicesOutboundIdTddAbandonRequest"
responses:
"200":
description: Obligation abandoned (dispatch_status=failed, not_transmitted_hold).
content:
application/json:
schema:
type: object
properties:
documentId:
type: string
format: uuid
required:
- documentId
"400":
description: reason_required — a required free-text reason is missing/empty.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: invalid_state — the parent already transmitted; it must generate.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/tdd/download:
get:
tags:
- invoices-outbound
summary: Signed URL for the generated TDD XML
description: 5-minute signed URL for the SK TDD (Tax Data Document) generated
from this invoice.
operationId: get_api_v1_invoices_outbound_id_tdd_download
x-source: portal
x-service:
- portal
x-rbac: outbound_document:read + tdd_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ url: string } — 5-minute signed Storage URL"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/{id}/tdd/reopen:
post:
tags:
- invoices-outbound
summary: Reopen (un-abandon) a C2 SK TDD obligation (Plan 164)
description: "The symmetric un-abandon: returns an abandoned obligation to
awaiting (dispatch_status=not_applicable) so it regenerates on the
parent’s next transmit. Required JSON { reason }. 400 reason_required;
409 invalid_state if there is no abandoned row; 404/403 as for abandon."
operationId: post_api_v1_invoices_outbound_id_tdd_reopen
x-source: portal
x-service:
- api-internal
x-rbac: tdd_document:read_write + tenant-scope + account-active (FR-11)
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1InvoicesOutboundIdTddReopenRequest"
responses:
"200":
description: Obligation reopened (dispatch_status=not_applicable, awaiting).
content:
application/json:
schema:
type: object
properties:
documentId:
type: string
format: uuid
required:
- documentId
"400":
description: reason_required — a required free-text reason is missing/empty.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
"409":
description: invalid_state — there is no abandoned obligation to reopen.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/invoices/outbound/export:
get:
tags:
- invoices-outbound
summary: CSV export of the sent-invoices list
description: "CSV export honoring the same filters as the list page (state,
document_type, company, q free-text search over invoice
no./seller/buyer/amount, date_from/date_to upload-date range,
validation, tdd) via the shared buildOutboundListQuery. Columns mirror
the table (Actions excluded; Company only for providers; Amount +
Currency split). ?locale= (sk|en, default sk) for CSV labels.
Rate-limited; capped at 10 000 rows. Audit-before-bytes: the exported
row count is recorded before any CSV is emitted."
operationId: get_api_v1_invoices_outbound_export
x-source: portal
x-service:
- portal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: state
in: query
required: false
schema:
type: string
- name: document_type
in: query
required: false
schema:
type: string
- name: company
in: query
required: false
schema:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- name: q
in: query
required: false
schema:
type: string
- name: date_from
in: query
required: false
schema:
type: string
- name: date_to
in: query
required: false
schema:
type: string
- name: validation
in: query
required: false
schema:
type: string
enum:
- passed
- failed
- name: tdd
in: query
required: false
schema:
type: string
enum:
- required
- not_required
- name: locale
in: query
required: false
schema:
type: string
enum:
- sk
- en
responses:
"200":
description: text/csv attachment (sent-invoices.csv)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/kb/{code}:
get:
tags:
- knowledge-base
summary: One localized knowledge (help) article by code
description: Auth-only read of an ACTIVE ref.knowledge_article, localized
(?locale=sk|en, row-level fallback requested→sk→en). Powers the "i" info
modal. 404 when the code is missing or inactive.
operationId: get_api_v1_kb_code
x-source: portal
x-service:
- portal
x-rbac: any authenticated session (ref.knowledge_article* are authenticated_read)
x-scope: n/a
x-audited: false
x-auth-kind: session
x-try-it-out: true
parameters:
- name: code
in: path
required: true
schema:
type: string
- name: locale
in: query
required: false
schema:
type: string
enum:
- sk
- en
responses:
"200":
description: "{ code, title, whatItIs, purpose, whyIssued, whenIssued,
whenNotIssued }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/org/integration-keys:
post:
tags:
- org
summary: Mint a scoped tenant integration key (Bearer, api-internal)
description: "Plan 212 S3: the api-internal Bearer re-implementation of the
portal createIntegrationKey action (Plan 207). Re-checks
integration_key:read_write on the caller-Bearer client, mints the raw
key SERVER-SIDE, and calls org_create_integration_key on that caller
client (DB-side RBAC + audit actor unchanged). The plaintext key is
returned ONCE and never persisted/logged. Served only by api-internal;
the portal action file was removed at Plan 213 S2 — the browser now
reaches this route through the portal server-side write-proxy (POST
/api/_proxy/org/integration-keys)."
operationId: post_api_v1_org_integration_keys
x-source: portal
x-service:
- api-internal
x-rbac: integration_key:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: false
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1OrgIntegrationKeysRequest"
responses:
"200":
description: "{ status: 'ok', key, keyPrefix } | forbidden | invalid |
limit_reached | error"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"429":
description: limit_reached — the tenant is at its active-integration-key cap.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/org/users/{id}:
patch:
tags:
- org
summary: Edit an own-tenant user (name, role, phone)
description: "Plan 188: orchestrates the existing org_update_user RPC
(name/role, unchanged) plus a NEW phone edit — phone lives on
GoTrue-managed auth.users, so no RPC can reach it directly; this route
authorizes + audits via org_record_user_phone_change BEFORE calling the
Auth Admin API (audit-before-side-effect), and only when the value
actually changed. Email is intentionally NOT editable through this route
(operator decision) — the request schema has no email field and any sent
would be silently dropped."
operationId: patch_api_v1_org_users_id
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PatchApiV1OrgUsersIdRequest"
responses:
"200":
description: "{ ok: true, fullName: string|null, phone: string|null, roleId:
string|null }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/org/users/{id}/close-account:
post:
tags:
- org
summary: Tenant self-service member account closure (per-member
pseudonymization, irreversible)
description: Tenant-initiated closure of an own-tenant member = per-member
PSEUDONYMIZATION (never anonymization/hard-delete), IRREVERSIBLE.
org_close_user_account pseudonymizes the member (full_name/role_id
nulled, status=disabled — DSAR §5.2 reuse, row KEPT) + PII-free
app_user.account_closed audit (tenant-pinned, self-block 42501,
foreign/missing -> P0002 -> 404, idempotent already_closed) BEFORE the
route runs the best-effort GoTrue scrub (tombstone email + permanent ban
+ delete MFA factors = session revoke). Never returns a
session/token/email.
operationId: post_api_v1_org_users_id_close_account
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ ok: true, closure: {...}, authScrub: {...} }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/org/users/{id}/resend-invite:
post:
tags:
- org
summary: Resend the invite email to a never-signed-in own-tenant member
description: org_resend_invite authorizes + audits + gates on status='invited'
(else 22023 -> 409; tenant-pinned, foreign/missing -> P0002 -> 404)
BEFORE the route re-sends the invite via the Auth Admin API
(generateLink({type:"invite"})).
operationId: post_api_v1_org_users_id_resend_invite
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ ok: true }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/org/users/{id}/reset-mfa:
post:
tags:
- org
summary: Tenant self-service 2FA reset for an own-tenant member
description: The tenant analogue of /api/v1/admin/users/{id}/reset-mfa, no
requireProvider. org_reset_mfa authorizes + audits + clears the target’s
app.account_mfa_lockout (tenant-pinned, self-block) BEFORE the route
deletes every GoTrue factor via the service-role Auth Admin API. Never
mints/returns a session/token/secret; the affected user is emailed.
operationId: post_api_v1_org_users_id_reset_mfa
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ ok: true, factorsDeleted: number }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/org/users/{id}/send-password-reset:
post:
tags:
- org
summary: Send a self-service password-reset email to an own-tenant member
description: org_send_password_reset authorizes + audits (tenant-pinned;
foreign/missing -> P0002 -> 404) BEFORE the route emails a recovery link
via the Auth Admin API (generateLink({type:"recovery"})). The link/token
is never returned to the caller; distinct from provider
admin-set-password.
operationId: post_api_v1_org_users_id_send_password_reset
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ ok: true }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/org/users/invite:
post:
tags:
- org
summary: Invite a user into the caller’s OWN organization
description: "Tenant-scoped analogue of /api/v1/admin/users/invite:
app_user:read_write WITHOUT requireProvider, and NO tenantId in the body
— org_provision_user forces membership to app.current_tenant_id(). AAL2
+ service role (server-only). GoTrue sends the invite email; the
app_user row is created via the audited self-tenant org_provision_user
RPC; on provisioning failure the orphaned auth user is rolled back."
operationId: post_api_v1_org_users_invite
x-source: portal
x-service:
- api-internal
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1OrgUsersInviteRequest"
responses:
"201":
description: "{ ok: true, userId: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/participants/check:
get:
tags:
- participants
summary: RM-14/RM-07 SMP/SML capability check (API-only)
description: Rate-limited (bucket participant_check) + input validated to the
Adapter's own rules (participant scheme, doctype). Never a send gate —
purely informational. 502 lookup_failed on an upstream fault.
operationId: get_api_v1_participants_check
x-source: portal
x-service:
- api-internal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: participantId
in: query
required: true
schema:
type: string
- name: documentTypeId
in: query
required: true
schema:
type: string
responses:
"200":
description: "{ result: 'registered' | 'not_registered' | 'error', reason?:
string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"429":
description: rate_limited (bucket participant_check).
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"502":
description: lookup_failed — an upstream SMP/SML fault (never a send gate).
content:
application/json:
schema: *a1
"503":
description: rate_limit_failed — the limiter RPC failed (fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/profile:
patch:
tags:
- profile
summary: Self-edit the caller’s OWN full name + phone
description: "Plan 191: orchestrates the self-pinned profile_update_self RPC
(full_name only) plus a NEW phone edit — phone lives on GoTrue-managed
auth.users, so profile_record_phone_change authorizes + audits BEFORE
the route calls the Auth Admin API (audit-before-side-effect), only when
the value actually changed. The acting id is ALWAYS auth.uid() (never
taken from the body); email is intentionally NOT editable (request
schema has no email field)."
operationId: patch_api_v1_profile
x-source: portal
x-service:
- api-internal
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PatchApiV1ProfileRequest"
responses:
"200":
description: "{ ok: true, fullName: string, phone: string|null }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/profile/avatar:
post:
tags:
- profile
summary: Upload the caller’s OWN avatar (multipart, ≤500×500 image)
description: 'Plan 191: single multipart `file`, fail-closed validation — mime
image/webp|image/jpeg|image/png (the client encodes WebP where
supported, else JPEG for Safari<17/webviews), ≤256 KiB, and decoded
dimensions ≤500×500 via an in-repo image header parser (no sharp; never
trusts the client resize). Any failure or undeterminable dimensions →
400 { error: "invalid_image", reason }. The write goes through the
RLS-bound session client (profile_self_* self-folder policy pins it to
{auth.uid()}/avatar, extensionless with the real content-type — no
service_role for the write); then profile_touch_avatar() stamps the
cache-bust marker + audits. Returns a fresh signed URL.'
operationId: post_api_v1_profile_avatar
x-source: portal
x-service:
- api-internal
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
example: multipart/form-data
description: multipart/form-data with a single `file` field (image/webp, ≤256
KiB, ≤500×500).
responses:
"200":
description: "{ ok: true, avatarUrl: string|null }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/profile/password:
post:
tags:
- profile
summary: Verify the current password, then change it (sign-out-others)
description: 'Plan 191: the acting id is ALWAYS the session user. Verifies the
current password on a throwaway client (no cookie persistence) — wrong →
400 wrong_password (feeds the existing per-account lockout hook). On
success: updateUser({password}) on the session client,
signOut({scope:"others"}) (revokes OTHER sessions, KEEPS the current one
— no forced re-login), then record_auth_event(auth.password_changed).'
operationId: post_api_v1_profile_password
x-source: portal
x-service:
- api-internal
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1ProfilePasswordRequest"
responses:
"200":
description: "{ ok: true }"
content:
application/json:
schema:
type: object
"400":
description: wrong_password (current password did not verify) or invalid_input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/reports/export:
get:
tags:
- reports
summary: CSV export of the same periodic report
description: Rate-limit gate runs BEFORE any query/CSV construction so a 429 can
never leak partial CSV. ?locale=sk|en (default sk) localizes column
headers.
operationId: get_api_v1_reports_export
x-source: portal
x-service:
- portal
x-rbac: composite (outbound_document:read and/or inbound_document:read)
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: from
in: query
required: false
schema:
type: string
- name: to
in: query
required: false
schema:
type: string
- name: locale
in: query
required: false
schema:
type: string
enum:
- sk
- en
responses:
"200":
description: text/csv attachment
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"429":
description: rate_limited — the gate runs before any CSV is built (never leaks a
partial CSV).
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"503":
description: rate_limit_failed — the limiter RPC failed (fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/reports/summary:
get:
tags:
- reports
summary: Periodic tenant report (sent/received/TDD/evidence)
description: Aggregated in TS over RLS-scoped queries. Sent-by-outcome, received
count + C3-side MLS status, TDD volumes, evidence coverage. from/to
default to the previous calendar month; rate-limited.
operationId: get_api_v1_reports_summary
x-source: portal
x-service:
- api-internal
x-rbac: composite (outbound_document:read and/or inbound_document:read — no
all-or-nothing 403)
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: from
in: query
required: false
schema:
type: string
- name: to
in: query
required: false
schema:
type: string
responses:
"200":
description: Periodic report summary object
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"429":
description: rate_limited.
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"503":
description: rate_limit_failed — the limiter RPC failed (fail-closed).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/security/close-account:
get:
tags:
- auth
summary: The caller’s own pending closure (for the grace-window banner)
description: "Plan 192: the AAL2-gated security_my_pending_closure() RPC returns
the caller’s pending self-closure { dsar_id, scheduled_action_at } or
SQL NULL (self-read over the provider-read-only dsar_request).
Read-only, not audited."
operationId: get_api_v1_security_close_account
x-source: portal
x-service:
- api-internal
x-rbac: self
x-scope: self
x-audited: false
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: "{ pending: { dsar_id, scheduled_action_at } | null }"
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
post:
tags:
- auth
summary: Schedule a deferred, cancelable self-service account closure
description: "Plan 192: resolves account_closure_grace_days (DB→code,
service-role read of the provider-read-only system_setting) and files a
DEFERRED DSAR erasure via security_schedule_self_closure(grace). The
account stays ACTIVE (no ban, still loginnable to cancel); the DB
enforces a fresh-TOTP re-challenge (RE401 → 401 reauth_required), a
provider refusal (42501 → 403), and the last-admin block (P0001 → 409
last_admin_block). On success the route ALSO revokes the caller’s OTHER
sessions (the client performs a global signOut after the response)."
operationId: post_api_v1_security_close_account
x-source: portal
x-service:
- api-internal
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: "{ dsar_id: string|null, scheduled_action_at: string|null }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: reauth_required — a fresh TOTP re-challenge is required (re-verify,
then retry).
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"409":
description: last_admin_block — you are the last user who can manage this
organization.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/security/close-account/cancel:
post:
tags:
- auth
summary: Withdraw the caller’s own pending closure
description: "Plan 192: the AAL2-gated, no-op-safe
security_cancel_self_closure() RPC sets the caller’s pending row
status=withdrawn and nulls the schedule (audits dsar.withdrawn). The
account was never disabled during the grace window, so cancelling
restores the pre-request state. Returns the RPC jsonb status verbatim."
operationId: post_api_v1_security_close_account_cancel
x-source: portal
x-service:
- api-internal
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1SecurityCloseAccountCancelRequest"
responses:
"200":
description: "{ status: 'withdrawn', dsar_id } | { status: 'none_pending' }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/security/csp-report:
post:
tags:
- health
summary: CSP violation collector (browser Reporting API) — always 204
description: "Plan 226 §5.3: the same-origin endpoint the nonce CSP names in
report-to and report-uri. UNAUTHENTICATED BY DESIGN (a violating page
may have no session; the beacon is credential-less) and on the reviewed
CQ-1 api-auth-invariant allowlist. Accepts application/reports+json and
application/csp-report; any other content-type is a silent no-op. Writes
the RM-26 security_event sink under kind=csp_violation — never
audit.log, never actor_user_id/tenant_id. The payload is allowlisted by
construction to four scalars — effective directive, ORIGIN-ONLY blocked
URI, PATH-ONLY document route (query stripped), disposition — so
script-sample, source-file, line/column, referrer and original-policy
are never read (GDPR). Bounded at four independent layers: an 8 KiB
streamed body cap, the content-type gate, an in-process
30-rows-per-minute-per-instance window (far below the sink’s shared
500/min DB cap, so a flood cannot evict auth telemetry), and
identical-violation collapse. ALWAYS 204 with an empty body — no error
taxonomy, no oracle."
operationId: post_api_v1_security_csp_report
x-source: portal
x-service:
- portal
x-rbac: public
x-scope: platform
x-audited: false
x-auth-kind: public
x-try-it-out: false
responses:
"204":
description: empty body (204 for every outcome — accepted, dropped, capped or
malformed)
default:
$ref: "#/components/responses/ApiError"
security: []
/api/v1/security/sessions:
get:
tags:
- auth
summary: List the caller’s OWN active sessions (+ current session id)
description: "Plan 192: the AAL2-gated security_list_own_sessions() RPC returns
the caller’s auth.sessions rows (id, created_at, refreshed_at,
not_after, aal, user_agent, ip) pinned to auth.uid(); the route adds the
current session_id from the verified claims so the UI can flag/disable
the current row. Read-only, not audited."
operationId: get_api_v1_security_sessions
x-source: portal
x-service:
- api-internal
x-rbac: self
x-scope: self
x-audited: false
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: "{ sessions: SessionRow[], currentSessionId: string }"
content:
application/json:
schema:
type: object
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/security/sessions/{id}:
delete:
tags:
- auth
summary: Revoke ONE of the caller’s own sessions
description: "Plan 192: the AAL2-gated security_revoke_session(id) RPC DELETEs
auth.sessions where id = {id} AND user_id = auth.uid() (cascades
refresh_tokens). It refuses the CURRENT session (derived at the DB from
the JWT session_id → 22023 → 400 cannot_revoke_current); a
foreign/missing id never escapes auth.uid() (P0002 → 404). Audits
auth.session_revoked."
operationId: delete_api_v1_security_sessions_id
x-source: portal
x-service:
- api-internal
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: "{ ok: true }"
content:
application/json:
schema:
type: object
"400":
description: invalid_id (not a uuid) or cannot_revoke_current (the current
session).
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — the session id is not one of the caller’s own.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/security/sessions/revoke-others:
post:
tags:
- auth
summary: Sign out of all OTHER devices
description: "Plan 192: the AAL2-gated security_revoke_other_sessions() RPC
DELETEs every auth.sessions row for auth.uid() EXCEPT the current one
(derived at the DB from the JWT session_id, never a caller parameter).
Returns the number revoked; audits auth.other_sessions_revoked."
operationId: post_api_v1_security_sessions_revoke_others
x-source: portal
x-service:
- api-internal
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: "{ revoked: number }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/settings/archive-handover/{id}/confirm:
post:
tags:
- org
summary: Confirm receipt of the archive hand-over
description: The tenant admin’s explicit acknowledgement that the archive has
been taken into the client’s own keeping. Write-once and irrevocable (a
monotone guard refuses any later clearing or overwrite). Until it is
given, nothing on the short retention branch can be disposed of.
operationId: post_api_v1_settings_archive_handover_id_confirm
x-source: portal
x-service:
- api-internal
x-rbac: tenant:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: The hand-over is confirmed
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/settings/archive-handover/{id}/download:
get:
tags:
- org
summary: Download the prepared archive-hand-over export
description: "Returns a short-lived signed URL to the export ZIP (source XML +
attachments + PDF visualization + TDD + manifest.json + index.csv) for
the invoice XML we are about to stop keeping. Stamps downloaded_at on
first use. Tenant-pinned: a hand-over belonging to another tenant is a
masked 404. The export is a COPY — it shortens none of the provider’s
own delivery-evidence periods, and the client’s § 85o ods. 15 duty is
unaffected."
operationId: get_api_v1_settings_archive_handover_id_download
x-source: portal
x-service:
- api-internal
x-rbac: tenant:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: A short-lived signed download URL
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/status/documents:
get:
tags:
- status
summary: Paginated period list of own documents' status
description: Filters phase, state, from, to, page. 429 rate_limited (+
Retry-After) on rate-limit.
operationId: get_api_v1_status_documents
x-source: portal
x-service:
- api-internal
x-rbac: outbound_document:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: phase
in: query
required: false
schema:
type: string
- name: state
in: query
required: false
schema:
type: string
- name: from
in: query
required: false
schema:
type: string
- name: to
in: query
required: false
schema:
type: string
- name: page
in: query
required: false
schema:
type: integer
minimum: 1
maximum: 9007199254740991
responses:
"200":
description: Paginated list of status projections
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"429":
description: rate_limited — over the per-caller fixed-window limit.
content:
application/json:
schema: *a1
headers:
Retry-After:
description: Seconds to wait before retrying.
schema:
type: integer
"503":
description: rate_limit_failed — the limiter RPC failed (fail-closed, never open).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/status/documents/{identifier}:
get:
tags:
- status
summary: Consolidated status projection for one own document (FR-52/UC-18)
description: ?type=invoice_uuid|transmission_uuid|client_reference selects the
lookup key. Unknown type -> 400; foreign/unknown id -> identical 404 (no
existence leakage).
operationId: get_api_v1_status_documents_identifier
x-source: portal
x-service:
- api-internal
x-rbac: outbound_document:read (+ tdd_document:read to include the tdd phase)
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: identifier
in: path
required: true
schema:
type: string
- name: type
in: query
required: true
schema:
type: string
enum:
- invoice_uuid
- transmission_uuid
- client_reference
responses:
"200":
description: Consolidated { peppolDelivery, mls, tdd, ... } status projection
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/telemetry/client-error:
post:
tags:
- health
summary: Browser error relay (OpenTelemetry) — always 204
description: "Plan 236 §1.2: the same-origin relay that replaced the Sentry
browser SDK. The browser posts a small JSON payload and the SERVER emits
the OTel log record — so the PII scrub runs server-side (a browser is
attacker-controlled) and no OneUptime ingest token ever ships to a
visitor. UNAUTHENTICATED BY DESIGN (global-error.tsx renders when the
root layout itself threw, so the errors most worth capturing have no
session) and on the reviewed CQ-1 api-auth-invariant allowlist. Mirrors
the Plan 226 CSP collector bound-for-bound: 8 KiB streamed body cap,
application/json gate, an in-process 30-records-per-minute-per-instance
window, identical-error collapse, and ALWAYS 204 with an empty body — no
error taxonomy, no oracle, no attribution read or set. The payload is
allowlisted by construction to name, message, stack and a PATH-ONLY
document route with UUID/numeric segments collapsed to :id; the two
free-text fields are additionally redacted at the OTLP exporter."
operationId: post_api_v1_telemetry_client_error
x-source: portal
x-service:
- portal
x-rbac: public
x-scope: platform
x-audited: false
x-auth-kind: public
x-try-it-out: false
responses:
"204":
description: empty body (204 for every outcome — accepted, dropped, capped or
malformed)
default:
$ref: "#/components/responses/ApiError"
security: []
/api/v1/telemetry/rum:
post:
tags:
- health
summary: Browser RUM relay (OTLP/HTTP JSON traces) — always 204
description: "Plan 238 §4.3: the same-origin relay the browser's OpenTelemetry
Web SDK exports to. The SERVER attaches the OneUptime ingest token and
forwards the batch, so NO ingest token ever reaches a visitor's page
(Plan 235 R-7 ceases to exist) and the CSP connect-src is never widened
to a third-party origin (RUM is same-origin, covered by 'self').
service.name is FORCED to portal-browser server-side and is never read
from the payload — otherwise an anonymous poster could publish spans
that appear to come from api-internal. UNAUTHENTICATED BY DESIGN (the
document-load span exists before a session does) and on the reviewed
CQ-1 api-auth-invariant allowlist. Mirrors the CSP collector and the
error relay bound-for-bound: a 128 KiB streamed body cap, an
application/json gate, an in-process 60-batches-per-minute-per-instance
window, structural batch bounds (4 resourceSpans / 8 scopeSpans / 256
spans / 64 attributes), and ALWAYS 204 with an empty body — no error
taxonomy, no oracle, no attribution read or set. Every posted span is
REBUILT server-side through Plan 236's attribute allowlist and free-text
redaction, so URLs lose their query, headers are dropped as a namespace
and unknown fields do not survive. The forward to OneUptime is
fire-and-forget; with OTEL_EXPORTER_OTLP_ENDPOINT unset the route
accepts and drops."
operationId: post_api_v1_telemetry_rum
x-source: portal
x-service:
- portal
x-rbac: public
x-scope: platform
x-audited: false
x-auth-kind: public
x-try-it-out: false
responses:
"204":
description: empty body (204 for every outcome — accepted, dropped, capped or
malformed)
default:
$ref: "#/components/responses/ApiError"
security: []
/api/v1/trace/documents/{identifier}:
get:
tags:
- trace
summary: End-to-end document trace (ingest→validation→send/AS4→MLS→TDD + audit
legs)
description: ?type=document_id|invoice_number|invoice_uuid|transmission_uuid|client_reference|tax_id|participant_id
selects the resolver. Unknown type/bad identifier -> 400;
foreign/unknown id -> 404. tax_id/participant_id resolving to >1 doc
return a disambiguation list. For transmission_uuid with no outbound
match, falls back to the inbound-origin trace (RM-13). document_id
resolves on the outbound_document PK (Plan 144 D19) — always present and
unique, so a caller holding the document links straight to its trace;
resolved under the same RLS client, so it leaks no more than any other
type.
operationId: get_api_v1_trace_documents_identifier
x-source: portal
x-service:
- api-internal
x-rbac: "outbound_document:read OR inbound_document:read (per-leg:
tdd_document:read, audit_log:read)"
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: identifier
in: path
required: true
schema:
type: string
- name: type
in: query
required: true
schema:
type: string
enum:
- document_id
- invoice_number
- invoice_uuid
- transmission_uuid
- client_reference
- tax_id
- participant_id
responses:
"200":
description: Full document trace envelope (per-leg gated; disambiguation list on
multi-match)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
"404":
description: not_found — unknown id, or a cross-tenant id masked as not-found
(anti-leakage).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/api/v1/webhooks/inbound:
post:
tags:
- webhooks
summary: Adapter inbound-webhook receiver
description: Fetch+verify opaque-payloadRef payload (+payloadSha256) ->
document-type dispatch -> fail-closed receiver->tenant resolve -> store
-> transact, all before 200 (custody stays Adapter-side until then).
Idempotent on transmissionId; may shed with 429/503 (custody-preserving,
retryable).
operationId: post_api_v1_webhooks_inbound
x-source: portal
x-service:
- api-internal
x-rbac: service-auth
x-scope: platform
x-audited: true
x-auth-kind: service-auth
x-try-it-out: false
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
- name: X-Timestamp
in: header
required: true
schema:
type: string
description: Epoch-seconds timestamp folded into the signed HMAC canonical
string; ±300s replay window (webhook-hmac.ts). Paired with the
`X-Signature` HMAC — see `security`.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1WebhooksInboundRequest"
responses:
"200":
description: "'200' (stored) | '200 mls_stored' | 429/503 (shed, retryable)"
content:
application/json:
schema:
type: object
"400":
description: invalid_* — malformed body or missing signature headers.
content:
application/json:
schema: *a1
"401":
description: invalid_signature / stale_timestamp (bad HMAC).
content:
application/json:
schema: *a1
"413":
description: payload_too_large — over the 20 MiB body cap.
content:
application/json:
schema: *a1
"429":
description: server_busy — burst-shed AFTER HMAC verify (in-flight cap). Custody
stays with the Adapter, which retries.
content:
application/json:
schema: *a1
"503":
description: fail-closed — signing secret unconfigured, or a transient store
failure (custody stays with the Adapter, which retries).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- hmacSignature: []
/api/v1/webhooks/send-status:
post:
tags:
- webhooks
summary: Advance the outbound send state (terminal-only push)
description: Emitted by the real Adapter after the durable transmit-store
transition commits — never for accepted/replays/non-terminal outcomes.
Advances via the chained send_advance_state RPC (idempotent no-op
re-advance returns 200 {noop:true}). Body carries an optional base64
receipt and an optional rejectReason.
operationId: post_api_v1_webhooks_send_status
x-source: portal
x-service:
- api-internal
x-rbac: service-auth
x-scope: platform
x-audited: true
x-auth-kind: service-auth
x-try-it-out: false
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
- name: X-Timestamp
in: header
required: true
schema:
type: string
description: Epoch-seconds timestamp folded into the signed HMAC canonical
string; ±300s replay window (webhook-hmac.ts). Paired with the
`X-Signature` HMAC — see `security`.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1WebhooksSendStatusRequest"
responses:
"200":
description: "{ noop?: true } or void on a fresh state transition"
content:
application/json:
schema:
type: object
"400":
description: invalid_* — malformed body or missing signature headers.
content:
application/json:
schema: *a1
"401":
description: invalid_signature / stale_timestamp (bad HMAC).
content:
application/json:
schema: *a1
"404":
description: not_found — unknown documentId (send_advance_state P0002).
content:
application/json:
schema: *a1
"413":
description: payload_too_large — over the 1 MiB body cap.
content:
application/json:
schema: *a1
"503":
description: fail-closed — signing secret unconfigured, or a transient store
failure (custody stays with the Adapter, which retries).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- hmacSignature: []
/api/v1/webhooks/stripe:
post:
tags:
- webhooks
summary: Stripe->portal billing sink (source of truth for billing state)
description: The portal's OWN SaaS subscription billing (NOT eFaktura). Verifies
the Stripe signature over the raw body BEFORE any effect (invalid ->
400, nothing written; disabled -> 503); livemode cross-check (mismatch
-> 200 + webhook_unmapped, no write); crash-safe idempotency via
ops.stripe_event (duplicate -> 200 skip, retry reprocesses); fail-closed
customer->tenant map (unmapped -> 200 + unmapped flag +
webhook_unmapped, never guessed). Handlers write via service-role
SECURITY DEFINER RPCs. Never logs the secret, a PAN, or bearer invoice
urls.
operationId: post_api_v1_webhooks_stripe
x-source: portal
x-service:
- api-internal
- portal
x-rbac: service-auth
x-scope: platform
x-audited: true
x-auth-kind: service-auth
x-try-it-out: false
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
- name: X-Timestamp
in: header
required: true
schema:
type: string
description: Epoch-seconds timestamp folded into the signed HMAC canonical
string; ±300s replay window (webhook-hmac.ts). Paired with the
`X-Signature` HMAC — see `security`.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/PostApiV1WebhooksStripeRequest"
responses:
"200":
description: "'200 { received: true }' (processed | duplicate | unmapped |
livemode-skipped)"
content:
application/json:
schema:
type: object
"400":
description: invalid_signature / missing_signature — verify failed, nothing
written.
content:
application/json:
schema: *a1
"401":
description: invalid_signature / stale_timestamp (bad HMAC).
content:
application/json:
schema: *a1
"413":
description: payload_too_large — over the ~1 MiB body cap (pre-verify).
content:
application/json:
schema: *a1
"503":
description: stripe_disabled / claim_failed / resolve_failed / handler_failed
(retryable).
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- hmacSignature: []
/rest/v1/rpc/admin_add_participant_identifier:
post:
tags:
- participants
summary: Register one active {scheme}:{value} participant ID for a tenant
description: Trims and validates scheme/value (22023 if empty). Duplicate active
(scheme,value) raises 23505 (fail-closed).
operationId: admin_add_participant_identifier
x-source: postgrest
x-rbac: participant_identifier:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminAddParticipantIdentifierRequest"
responses:
"200":
description: "{ id: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_create_role:
post:
tags:
- admin-users
summary: Create a role
operationId: admin_create_role
x-source: postgrest
x-rbac: role:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminCreateRoleRequest"
responses:
"200":
description: "{ id: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_create_subscription_type:
post:
tags:
- admin-users
summary: Create a subscription package
description: Auto code; price/currency/interval — P-010.
operationId: admin_create_subscription_type
x-source: postgrest
x-rbac: subscription_type:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminCreateSubscriptionTypeRequest"
responses:
"200":
description: "{ id: string, code: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_create_tenant:
post:
tags:
- tenants
summary: Create a customer account
operationId: admin_create_tenant
x-source: postgrest
x-rbac: tenant:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminCreateTenantRequest"
responses:
"200":
description: "{ id: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_create_validation_rule:
post:
tags:
- validation-rules
summary: Create a validation rule (SUPERSEDED)
description: Superseded + dropped by P-097 (S3) — the register is now
version/deploy-controlled. Retained here for generator-completeness
only; the underlying function no longer exists.
operationId: admin_create_validation_rule
x-source: postgrest
x-rbac: validation_rules:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: false
responses:
"200":
description: n/a — function dropped by P-097
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_create_validation_rule_version:
post:
tags:
- validation-rules
summary: Insert a pending version row for a single uploaded XSLT + its derived SEF
description: Server-derives storage_path/sef_storage_path, traversal-safe
file_name; gated on managed_by=upload. Called by the upload route.
operationId: admin_create_validation_rule_version
x-source: postgrest
x-rbac: validation_rules:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminCreateValidationRuleVersionRequest"
responses:
"200":
description: "{ versionId: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_delete_help_article:
post:
tags:
- knowledge-base
summary: Delete a Help Center article
description: Deletes ref.help_article (i18n cascades). Audited help_article.delete.
operationId: admin_delete_help_article
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminDeleteHelpArticleRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_delete_help_category:
post:
tags:
- knowledge-base
summary: Delete a Help Center category
description: Deletes ref.help_category (i18n cascades). FK restrict raises if
any FAQ/article still references it. Audited help_category.delete.
operationId: admin_delete_help_category
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminDeleteHelpCategoryRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_delete_help_faq:
post:
tags:
- knowledge-base
summary: Delete a Help Center FAQ
description: Deletes ref.help_faq (i18n cascades). Audited help_faq.delete.
operationId: admin_delete_help_faq
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminDeleteHelpFaqRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_delete_knowledge_article:
post:
tags:
- knowledge-base
summary: Delete a knowledge article
description: Deletes the base row (i18n cascades). Audited
knowledge_base.delete. Any "i" referencing the code shows the missing
state until it is recreated.
operationId: admin_delete_knowledge_article
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminDeleteKnowledgeArticleRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_delete_ui_string_override:
post:
tags:
- knowledge-base
summary: Clear a UI-string override (revert the key/locale to the static bundle)
description: Deletes the ref.ui_string_override row for (key, locale) so the
static bundle value is served again. Raises P0002 if no override exists.
Audited ui_string_override.delete.
operationId: admin_delete_ui_string_override
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminDeleteUiStringOverrideRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_deploy_validation_changes:
post:
tags:
- validation-rules
summary: Atomic, serialized deploy of selected pending versions + staged changes
description: One validation_deployment (+items); FR-19a window guards.
operationId: admin_deploy_validation_changes
x-source: postgrest
x-rbac: validation_rules:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminDeployValidationChangesRequest"
responses:
"200":
description: "{ deploymentId: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_discard_validation_pending:
post:
tags:
- validation-rules
summary: Hard-delete a pending version row or discard a staged change
description: File/SEF identity folds inline (D6) — no separate artifact rows to
cascade; audit keeps the sha256 manifest.
operationId: admin_discard_validation_pending
x-source: postgrest
x-rbac: validation_rules:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminDiscardValidationPendingRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_list_settings:
post:
tags:
- settings
summary: List settings with effective value + source
description: source ∈ db | env | code.
operationId: admin_list_settings
x-source: postgrest
x-rbac: system_setting:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Array of { key, value, source }
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_provision_user:
post:
tags:
- admin-users
summary: Link an invited auth user as a tenant member
operationId: admin_provision_user
x-source: postgrest
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminProvisionUserRequest"
responses:
"200":
description: "{ id: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_reset_mfa:
post:
tags:
- auth
summary: Authorize + audit an admin 2FA reset (P-088 S2)
description: Authorizes + audits an admin 2FA reset and clears the target's
app.account_mfa_lockout. Deletes no GoTrue rows (the
/api/v1/admin/users/{id}/reset-mfa route does that with the service
role). Missing target -> P0002 -> 404.
operationId: admin_reset_mfa
x-source: postgrest
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminResetMfaRequest"
responses:
"200":
description: void (lockout cleared, audit row written)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_revert_validation_deployment:
post:
tags:
- validation-rules
summary: Two-step revert of the latest deployment (exact inverse)
operationId: admin_revert_validation_deployment
x-source: postgrest
x-rbac: validation_rules:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminRevertValidationDeploymentRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_help_article_active:
post:
tags:
- knowledge-base
summary: (De)activate a Help Center article
description: Flips ref.help_article.is_active for a slug. Audited
help_article.set_active.
operationId: admin_set_help_article_active
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetHelpArticleActiveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_help_category_active:
post:
tags:
- knowledge-base
summary: (De)activate a Help Center category
description: Flips ref.help_category.is_active for a code. Audited
help_category.set_active.
operationId: admin_set_help_category_active
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetHelpCategoryActiveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_help_faq_active:
post:
tags:
- knowledge-base
summary: (De)activate a Help Center FAQ
description: Flips ref.help_faq.is_active for an id. Audited help_faq.set_active.
operationId: admin_set_help_faq_active
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetHelpFaqActiveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_knowledge_article_active:
post:
tags:
- knowledge-base
summary: (De)activate a knowledge article
description: Flips ref.knowledge_article.is_active for a code. Audited
knowledge_base.set_active.
operationId: admin_set_knowledge_article_active
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetKnowledgeArticleActiveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_participant_identifier_active:
post:
tags:
- participants
summary: Activate or deactivate an existing participant ID
description: Raises P0002 if row not found. Reactivating into a conflicting
active (scheme,value) raises 23505. No hard delete — deactivated rows
preserved for audit history.
operationId: admin_set_participant_identifier_active
x-source: postgrest
x-rbac: participant_identifier:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetParticipantIdentifierActiveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_role_active:
post:
tags:
- admin-users
summary: Activate / deactivate a role (system protected)
operationId: admin_set_role_active
x-source: postgrest
x-rbac: role:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetRoleActiveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_role_permissions:
post:
tags:
- admin-users
summary: Replace a role's permission matrix (system protected)
operationId: admin_set_role_permissions
x-source: postgrest
x-rbac: role:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetRolePermissionsRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_subscription_type_active:
post:
tags:
- admin-users
summary: Activate / deactivate a package
description: P-010.
operationId: admin_set_subscription_type_active
x-source: postgrest
x-rbac: subscription_type:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetSubscriptionTypeActiveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_subscription_type_features:
post:
tags:
- admin-users
summary: Replace a package's enabled features
description: P-010.
operationId: admin_set_subscription_type_features
x-source: postgrest
x-rbac: subscription_type:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetSubscriptionTypeFeaturesRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_tenant_status:
post:
tags:
- tenants
summary: active/suspended/closed (the provider account is locked)
operationId: admin_set_tenant_status
x-source: postgrest
x-rbac: tenant:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetTenantStatusRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_user_status:
post:
tags:
- admin-users
summary: Change user status (cannot change one's own)
operationId: admin_set_user_status
x-source: postgrest
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetUserStatusRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_set_validation_rule_active:
post:
tags:
- validation-rules
summary: Break-glass emergency (de)activation
description: Re-expressed via status by P-097 — deactivate ⇒ status='reverted',
activate ⇒ status='deployed'.
operationId: admin_set_validation_rule_active
x-source: postgrest
x-rbac: validation_rules:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminSetValidationRuleActiveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_stage_validation_config_change:
post:
tags:
- validation-rules
summary: Stage the single pending per-rule flag change (inbound/outbound/blocking)
operationId: admin_stage_validation_config_change
x-source: postgrest
x-rbac: validation_rules:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminStageValidationConfigChangeRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_update_document_state:
post:
tags:
- validation-rules
summary: Edit is_active/severity/color_ui on a fixed state code + i18n label
description: UPSERTs label/description into ref.document_state_i18n for the
given locale (defaults 'sk').
operationId: admin_update_document_state
x-source: postgrest
x-rbac: document_state:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpdateDocumentStateRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_update_document_type:
post:
tags:
- validation-rules
summary: Edit is_active on a fixed type code + i18n label
description: p_is_enabled param (unchanged name). UPSERTs label/description into
ref.document_type_i18n for the given locale (defaults 'sk').
operationId: admin_update_document_type
x-source: postgrest
x-rbac: document_state:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpdateDocumentTypeRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_update_role:
post:
tags:
- admin-users
summary: Update a role (system roles protected)
operationId: admin_update_role
x-source: postgrest
x-rbac: role:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpdateRoleRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_update_setting:
post:
tags:
- settings
summary: Set/unset a setting value
description: Clamp-and-reject from the registry; before/after audited.
operationId: admin_update_setting
x-source: postgrest
x-rbac: system_setting:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpdateSettingRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_update_subscription_type:
post:
tags:
- admin-users
summary: Update a package
description: P-010.
operationId: admin_update_subscription_type
x-source: postgrest
x-rbac: subscription_type:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpdateSubscriptionTypeRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_update_tenant:
post:
tags:
- tenants
summary: Update an account (name, package, IČO, DIČ)
operationId: admin_update_tenant
x-source: postgrest
x-rbac: tenant:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpdateTenantRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_update_user:
post:
tags:
- admin-users
summary: Update a user's name + assigned role
operationId: admin_update_user
x-source: postgrest
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpdateUserRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_update_validation_rule:
post:
tags:
- validation-rules
summary: Update all editable fields (SUPERSEDED)
description: Superseded + dropped by P-097 (S3). Retained here for
generator-completeness only; the underlying function no longer exists.
operationId: admin_update_validation_rule
x-source: postgrest
x-rbac: validation_rules:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: false
responses:
"200":
description: n/a — function dropped by P-097
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_upsert_help_article:
post:
tags:
- knowledge-base
summary: Create or edit a Help Center article (both locales)
description: UPSERTs ref.help_article + both sk+en title/body rows. p_content =
{"sk":{title,body},"en":{…}}; slug must be kebab-case + both locales
required (else 22023). Slug is immutable (the /help/[slug] key).
operationId: admin_upsert_help_article
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpsertHelpArticleRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_upsert_help_category:
post:
tags:
- knowledge-base
summary: Create or edit a Help Center category (both locales)
description: UPSERTs ref.help_category + both sk+en label rows. p_content =
{"sk":{label},"en":{label}}; code + style + both labels required (else
22023).
operationId: admin_upsert_help_category
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpsertHelpCategoryRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_upsert_help_faq:
post:
tags:
- knowledge-base
summary: Create or edit a Help Center FAQ (both locales)
description: UPSERTs ref.help_faq + both sk+en question/answer rows (p_id null →
new uuid_v7). p_content = {"sk":{question,answer},"en":{…}}; both
locales required (else 22023). Returns the FAQ id.
operationId: admin_upsert_help_faq
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpsertHelpFaqRequest"
responses:
"200":
description: uuid (the FAQ id)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_upsert_knowledge_article:
post:
tags:
- knowledge-base
summary: Create or edit a knowledge article (both locales)
description: UPSERTs the base row + both sk+en ref.knowledge_article_i18n rows.
p_content = {"sk":{title,whatItIs,…},"en":{…}}; title+whatItIs required
in both locales (else 22023).
operationId: admin_upsert_knowledge_article
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpsertKnowledgeArticleRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/admin_upsert_ui_string_override:
post:
tags:
- knowledge-base
summary: Create or edit a UI-string override for a message key + locale
description: UPSERTs ref.ui_string_override(key, locale, value). Non-empty key +
value required and the locale must exist (else 22023). ICU validity is
NOT checked here — the render-path loader is the authoritative
parse-and-drop gate. Audited ui_string_override.upsert.
operationId: admin_upsert_ui_string_override
x-source: postgrest
x-rbac: knowledge_base:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AdminUpsertUiStringOverrideRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/complete_sign_in:
post:
tags:
- auth
summary: Post-login account-state gate
description: Records auth.login_success / auth.login_denied. Called once per
successful 2FA sign-in.
operationId: complete_sign_in
x-source: postgrest
x-rbac: authenticated (post-2FA)
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Account-state gate result (allowed / denied reason)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/current_permissions:
post:
tags:
- auth
summary: Caller's effective permission set
description: Used for nav gating / control disabling.
operationId: current_permissions
x-source: postgrest
x-rbac: authenticated
x-scope: self
x-audited: false
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Array of { resource, level } permission grants
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/dlq_discard:
post:
tags:
- dlq
summary: Audited terminal "discard" annotation on a DLQ item
description: No row deletion — retention floors are never weakened. Sets
dlq_discarded_at=now() on the underlying document row.
operationId: dlq_discard
x-source: postgrest
x-rbac: dlq_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DlqDiscardRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/dlq_list:
post:
tags:
- dlq
summary: List dead-lettered/terminal items for the DLQ runbook UI
description: Across the four DLQ-adjacent classes (send_exhausted,
send_rejected, sender_unverified, inbound_exhausted). Filters out any
row with dlq_discarded_at set.
operationId: dlq_list
x-source: postgrest
x-rbac: dlq_ops:read
x-scope: platform
x-audited: false
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: Array of DLQ items across the four classes
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/dlq_requeue:
post:
tags:
- dlq
summary: Requeue a DLQ item by kind
description: send_exhausted via an inline ready_for_peppol transition (provider
cross-tenant path); inbound_exhausted via requeue_inbound_delivery. Both
clear dlq_discarded_at. Never back through the validation pipeline
(N21).
operationId: dlq_requeue
x-source: postgrest
x-rbac: dlq_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DlqRequeueRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/get_outbound_document_audit_trail:
post:
tags:
- audit
summary: Audit timeline for a single outbound document
description: Returns seq, occurred_at, actor_full_name, action, outcome, before,
after; before/after NULL unless caller holds audit_log_detail:read.
Never exposes prev_hash/row_hash/source_ip/user_agent.
operationId: get_outbound_document_audit_trail
x-source: postgrest
x-rbac: audit_log:read (rows) · audit_log_detail:read (before/after)
x-scope: tenant
x-audited: false
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/GetOutboundDocumentAuditTrailRequest"
responses:
"200":
description: Array of audit timeline rows
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/inbound_delivery_release:
post:
tags:
- dlq
summary: Release a content-invalid reception to the recipient agent (audited
override)
description: Stamps inbound_document.delivery_released_at so inbound_pull_next
offers a reception whose content_validation_status is "failed" (Plan 134
§5.6 withholds it — SA §6.4.1 "invalid → no forward"). Guarded to failed
only (P0001 otherwise) and idempotent-by-refusal (a second release
raises rather than re-auditing). Never rewrites
content_validation_status — that field is the BV MLS evidence anchor, so
the BV asserted to C2 stands. Custody is unaffected either way.
operationId: inbound_delivery_release
x-source: postgrest
x-rbac: dlq_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/InboundDeliveryReleaseRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/legal_hold_place:
post:
tags:
- legal-hold
summary: Place a legal hold on a record
description: "kind ∈
outbound_document/inbound_document/tdd_document/quarantine_item/audit_l\
og/tenant. Fail-closed: target must exist (404), reason+owner non-empty
(400). Deletion of the held record is then blocked at the DB
(LH-02/LH-05)."
operationId: legal_hold_place
x-source: postgrest
x-rbac: legal_hold:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/LegalHoldPlaceRequest"
responses:
"200":
description: "{ id: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/legal_hold_release:
post:
tags:
- legal-hold
summary: Release a hold (active -> released, one-way)
description: The record re-enters standard retention on the next sweep (LH-07).
Non-empty release reason required; double-release errors.
operationId: legal_hold_release
x-source: postgrest
x-rbac: legal_hold:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/LegalHoldReleaseRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/legal_hold_report:
post:
tags:
- legal-hold
summary: List holds enriched with a per-kind target descriptor + full_name
description: Never email. Optional active/released filter (LH-08). Returns
display metadata only — never invoice XML.
operationId: legal_hold_report
x-source: postgrest
x-rbac: legal_hold:read
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/LegalHoldReportRequest"
responses:
"200":
description: Array of enriched legal_hold rows
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/log_admin_session_ban:
post:
tags:
- admin-users
summary: Audit the GoTrue ban/unban side-effect of a status change (Plan 169 M8)
description: "Called by the /api/v1/admin/users/{id}/status route after the
ban/unban applies (the status RPC audits app_user.status_change
separately). Records app_user.session_ban / app_user.session_unban
scoped to the target's tenant. Default-deny: provider +
app_user:read_write; missing target -> 404."
operationId: log_admin_session_ban
x-source: postgrest
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/LogAdminSessionBanRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/log_org_user_list_view:
post:
tags:
- org
summary: Fail-closed sensitive-read audit for the Org › Users email-merge
description: Tenant-self variant of the provider-only log_app_user_list_view;
authorizes on app_user:read and stamps the caller’s own tenant. Records
app_user.list_view.
operationId: log_org_user_list_view
x-source: postgrest
x-rbac: app_user:read
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/notify_account_security_event:
post:
tags:
- auth
summary: Send a canned account-security notice
description: Sends a canned security_notice.* notice (in-app + unconditional
email) to a single recipient. Independently callable by any provider
admin, not only from the reset flow — accepted residual (fail-closed
template whitelist, no free-content injection, every call audited).
operationId: notify_account_security_event
x-source: postgrest
x-rbac: app_user:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/NotifyAccountSecurityEventRequest"
responses:
"200":
description: "{ notificationId: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_add_participant_identifier:
post:
tags:
- org
summary: Self-register an active {scheme}:{value} for the caller’s own tenant
description: "Anti-hijack: the normalized value must match the tenant’s own
IČO/DIČ/IČ-DPH (42501 otherwise); duplicate active (scheme,value) →
23505. Non-ICO/DIC schemes stay provider-only."
operationId: org_add_participant_identifier
x-source: postgrest
x-rbac: participant_identifier:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgAddParticipantIdentifierRequest"
responses:
"200":
description: "{ id: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_close_user_account:
post:
tags:
- org
summary: Pseudonymize + disable ONE own-tenant member (DB half of member account
closure)
description: "Plan 189 (S1): app.assert_tenant_write('app_user'), pinned to
app.current_tenant_id() (foreign/missing target -> P0002); self-block
(42501). Applies the DSAR §5.2 user-level scrub (full_name/role_id null,
status=disabled — row KEPT as FK anchor / audit pseudonym; the DIČ key
lives on tenant, untouched) + PII-free app_user.account_closed audit;
idempotent (second call -> already_closed, no second audit). A CLOSED
member can never be reactivated (org_set_user_status §5.3 guard ->
42501). The /api/v1/org/users/{id}/close-account route runs the GoTrue
scrub after this commits."
operationId: org_close_user_account
x-source: postgrest
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgCloseUserAccountRequest"
responses:
"200":
description: jsonb { status, user_id, tenant_id, auth_scrub_required }
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_create_integration_key:
post:
tags:
- org
summary: Create a tenant integration key (Plan 207)
description: The ROUTE mints the key server-side; this RPC receives the SHA-256
bytea + display prefix (never plaintext). Validates the scope set
(subset of {lookup:single,lookup:bulk}, 22023), enforces the
integration_key_max_active cap (42501 over it), stamps created_by,
audits integration_key.create (no hash in the detail).
app.assert_tenant_write(integration_key).
operationId: org_create_integration_key
x-source: postgrest
x-rbac: integration_key:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgCreateIntegrationKeyRequest"
responses:
"200":
description: "{ id: string }"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_list_integration_keys:
post:
tags:
- org
summary: List the caller’s OWN tenant integration keys (Plan 207)
description: Safe projection only —
id/label/key_prefix/scopes/is_active/last_used_at/created_at; NEVER
key_hash. Read-gated on integration_key:read; tenant-pinned SECURITY
DEFINER (the table has no authenticated grant).
operationId: org_list_integration_keys
x-source: postgrest
x-rbac: integration_key:read
x-scope: tenant
x-audited: false
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgListIntegrationKeysRequest"
responses:
"200":
description: "{ id, label, key_prefix, scopes, is_active, last_used_at,
created_at }[]"
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_provision_user:
post:
tags:
- org
summary: Link an invited auth user into the caller’s OWN tenant
description: Tenant forced to app.current_tenant_id() (no tenant param). The
app.check_user_role_scope trigger backstops platform-role assignment to
a customer-tenant user.
operationId: org_provision_user
x-source: postgrest
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgProvisionUserRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_record_user_phone_change:
post:
tags:
- org
summary: Authorize + audit an own-tenant user’s phone edit
description: "Plan 188 (S2): app.assert_tenant_write('app_user'), pinned to
app.current_tenant_id() (foreign/missing id → P0002); no self-block
(editing one’s own phone is allowed, mirrors org_update_user). Appends
app_user.phone_changed with before/after values. Does NOT touch
auth.users itself — the route calls the Auth Admin API after this RPC
commits."
operationId: org_record_user_phone_change
x-source: postgrest
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgRecordUserPhoneChangeRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_request_release:
post:
tags:
- org
summary: Release (deregister) all of the caller’s OWN participant identifiers
description: "SML release/deregistration: deactivates AND stamps deregistered_at
on every active participant identifier of the caller’s OWN tenant
(deactivate + mark, no hard delete); returns the count released.
SECURITY DEFINER, app.assert_tenant_write('participant_identifier'),
pinned to app.current_tenant_id() (no current tenant → P0002);
before/after audit (participant_identifier.released). The real
SML-record deletion at FS SR is mocked/deferred until FS SR is wired up
(Plan 181). No request body."
operationId: org_request_release
x-source: postgrest
x-rbac: participant_identifier:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: number (count of identifiers released)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_reset_mfa:
post:
tags:
- org
summary: Authorize + audit a tenant self-service 2FA reset
description: AAL2 asserted explicitly. app.assert_tenant_write('app_user'),
pinned to app.current_tenant_id() (foreign/missing target -> P0002);
self-block (42501, mirrors org_set_user_status). Clears
app.account_mfa_lockout and appends auth.mfa_reset_by_org_admin. Deletes
NO GoTrue rows — the /api/v1/org/users/{id}/reset-mfa route does that
with the service role.
operationId: org_reset_mfa
x-source: postgrest
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgResetMfaRequest"
responses:
"200":
description: void (lockout cleared, audit row written)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_revoke_integration_key:
post:
tags:
- org
summary: Revoke a tenant integration key (Plan 207)
description: Sets is_active=false (no hard delete). Tenant-pinned — another
tenant’s id → P0002 not-found (no cross-tenant revoke). Audits
integration_key.revoke (no hash). Rotation = create + revoke.
operationId: org_revoke_integration_key
x-source: postgrest
x-rbac: integration_key:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgRevokeIntegrationKeyRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_set_participant_identifier_active:
post:
tags:
- org
summary: (De)activate one of the caller’s OWN participant IDs
description: Pinned to app.current_tenant_id() (foreign id → P0002);
reactivating into a conflicting active (scheme,value) → 23505.
operationId: org_set_participant_identifier_active
x-source: postgrest
x-rbac: participant_identifier:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgSetParticipantIdentifierActiveRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_set_user_status:
post:
tags:
- org
summary: Change an own-tenant user’s status
description: invited/active/suspended/disabled; self-lockout denied (42501);
foreign id → P0002. before/after audit diff.
operationId: org_set_user_status
x-source: postgrest
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgSetUserStatusRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_update_details:
post:
tags:
- org
summary: Self-edit the caller’s OWN organization detail
description: Column-whitelisted self-tenant write (name, IČO, DIČ, IČ DPH,
registered address); never touches kind/status/subscription/closure.
SECURITY DEFINER, app.assert_tenant_write('tenant'), pinned to
app.current_tenant_id(); before/after audit diff.
operationId: org_update_details
x-source: postgrest
x-rbac: tenant:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgUpdateDetailsRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/org_update_user:
post:
tags:
- org
summary: Update an own-tenant user’s name + role
description: Pinned to app.current_tenant_id() (foreign id → P0002);
before/after audit diff.
operationId: org_update_user
x-source: postgrest
x-rbac: app_user:read_write
x-scope: tenant
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/OrgUpdateUserRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/profile_record_phone_change:
post:
tags:
- profile
summary: Authorize + audit the caller’s OWN phone edit
description: Audit-only mirror of org_record_user_phone_change, self-pinned to
auth.uid(). Appends app_user.phone_changed (before/after). Does NOT
touch auth.users — the route calls the Auth Admin API after this RPC
commits.
operationId: profile_record_phone_change
x-source: postgrest
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ProfileRecordPhoneChangeRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/profile_touch_avatar:
post:
tags:
- profile
summary: Mark the caller’s OWN avatar as changed
description: Sets avatar_updated_at = now() on id = auth.uid() (cache-bust
marker + "avatar exists" flag); audits app_user.avatar_changed. The
route uploads the object to the profile bucket separately. 28000 if no
session, P0002 if the row is missing.
operationId: profile_touch_avatar
x-source: postgrest
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/profile_update_self:
post:
tags:
- profile
summary: Self-edit the caller’s OWN app_user.full_name
description: SECURITY DEFINER, self-pinned to auth.uid() (whitelist full_name
only; 28000 if no session, P0002 if the row is missing). before/after
audit (app_user.self_updated). No RBAC resource — own row.
operationId: profile_update_self
x-source: postgrest
x-rbac: self
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ProfileUpdateSelfRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/record_auth_event:
post:
tags:
- auth
summary: Append a whitelisted auth event
description: Logout, MFA enrol/fail, password change — appended to the audit log.
operationId: record_auth_event
x-source: postgrest
x-rbac: authenticated
x-scope: self
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RecordAuthEventRequest"
responses:
"200":
description: void (audit row written)
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
/rest/v1/rpc/requeue_inbound_delivery:
post:
tags:
- dlq
summary: Recover an inbound_exhausted document back to delivery_pending
description: For re-offer to the agent. Also resets dlq_discarded_at=null.
operationId: requeue_inbound_delivery
x-source: postgrest
x-rbac: dlq_ops:read_write
x-scope: platform
x-audited: true
x-auth-kind: session
x-try-it-out: true
parameters:
- name: Content-Type
in: header
required: true
schema:
type: string
enum:
- application/json
description: The request body is JSON.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RequeueInboundDeliveryRequest"
responses:
"200":
description: void
content:
application/json:
schema:
type: object
"400":
description: validation_error — malformed input.
content:
application/json:
schema: *a1
"401":
description: unauthenticated — no valid AAL2 session.
content:
application/json:
schema: *a1
"403":
description: forbidden / mfa_required / account_inactive — authenticated but not
permitted.
content:
application/json:
schema: *a1
default:
$ref: "#/components/responses/ApiError"
security:
- sessionCookie: []
components:
schemas:
ApiError:
type: object
properties:
error:
type: string
correlationId:
type: string
required:
- error
- correlationId
PostApiV1AdminArchiveHandoversIdConfirmOutOfBandRequest:
type: object
properties:
confirmation_ref:
type: string
minLength: 1
maxLength: 200
reason:
type: string
minLength: 1
maxLength: 200
required:
- confirmation_ref
- reason
additionalProperties: false
PostApiV1AdminBottleneckCheckRunRequest:
type: object
properties:
reason:
type: string
maxLength: 500
additionalProperties: false
PostApiV1AdminIncidentsRequest:
type: object
properties:
category:
type: string
enum:
- technical
- validation
- client_data
- peppol
- c5
- security
severity:
type: string
enum:
- sev1
- sev2
- sev3
description:
type: string
required:
- category
- severity
additionalProperties: false
PostApiV1AdminIncidentsIdClassifyRequest:
type: object
properties:
nis2Status:
type: string
enum:
- not_assessed
- not_reportable
- reportable
rationale:
type: string
required:
- nis2Status
additionalProperties: false
PostApiV1AdminIncidentsIdNotifyRequest:
type: object
properties:
tenantId:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
templateKey:
type: string
severity:
type: string
enum:
- info
- warning
- critical
params:
type: object
propertyNames:
type: string
additionalProperties:
type: string
required:
- tenantId
- templateKey
- severity
additionalProperties: false
PostApiV1AdminIncidentsIdPriorityRequest:
type: object
properties:
priority:
type: string
enum:
- p1
- p2
- p3
reason:
type: string
required:
- priority
additionalProperties: false
PostApiV1AdminIncidentsIdResolveRequest:
type: object
properties:
resolution:
type: string
required:
- resolution
additionalProperties: false
PostApiV1AdminQuarantineIdResolveRequest:
type: object
properties:
tenantId:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- tenantId
additionalProperties: false
PostApiV1AdminRetentionRunRequest:
type: object
properties:
class:
type: string
enum:
- r1_outbound
- r2_inbound
- r3_tdd
- r4_quarantine_receipts
- r20_outbound_delivery_evidence
- r21_inbound_delivery_evidence
- r22_validation_evidence
mode:
type: string
enum:
- dry_run
- destructive
additionalProperties: false
PostApiV1AdminStripeConfigRequest:
type: object
properties:
enabled:
type: boolean
secretKey:
anyOf:
- type: string
- type: "null"
webhookSecret:
anyOf:
- type: string
- type: "null"
publishableKey:
anyOf:
- type: string
- type: "null"
required:
- enabled
- secretKey
- webhookSecret
- publishableKey
additionalProperties: false
PostApiV1AdminSubscriptionTypesStripeLinkRequest:
type: object
properties:
id:
type: string
name:
type: string
description:
anyOf:
- type: string
- type: "null"
amount:
anyOf:
- type: number
- type: "null"
currency:
type: string
interval:
type: string
enum:
- month
- year
productId:
anyOf:
- type: string
- type: "null"
priceId:
anyOf:
- type: string
- type: "null"
required:
- id
- name
- description
- amount
- currency
- interval
- productId
- priceId
additionalProperties: false
PostApiV1AdminTenantsIdInvoiceArchiveModeRequest:
type: object
properties:
mode:
type: string
enum:
- archive
- no_archive
contract_ref:
type: string
minLength: 1
maxLength: 200
reason:
type: string
minLength: 1
maxLength: 200
required:
- mode
- contract_ref
- reason
additionalProperties: false
PostApiV1AdminUsersIdResetPasswordRequest:
type: object
properties:
password:
type: string
minLength: 8
required:
- password
additionalProperties: false
PostApiV1AdminUsersIdStatusRequest:
type: object
properties:
status:
type: string
enum:
- active
- suspended
- disabled
required:
- status
additionalProperties: false
PostApiV1AdminUsersInviteRequest:
type: object
properties:
email:
type: string
format: email
pattern: ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
fullName:
type: string
maxLength: 200
tenantId:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
roleId:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- email
- tenantId
- roleId
additionalProperties: false
PostApiV1AdminValidationRulesVersionsRequest:
type: object
properties:
file:
type: string
description: multipart XSLT file (.xsl/.xslt)
ruleKey:
type: string
schemaVersion:
type: string
validFrom:
type: string
note:
type: string
required:
- file
- ruleKey
- schemaVersion
- validFrom
additionalProperties: false
PostApiV1AdminWorkersRestartRequest:
type: object
properties:
workerKind:
type: string
enum:
- invoice
- send
instanceId:
type: string
minLength: 1
reason:
type: string
minLength: 1
maxLength: 500
required:
- workerKind
- reason
additionalProperties: false
PostApiV1AgentInboundIdAckRequest:
type: object
properties:
ackToken:
type: string
required:
- ackToken
additionalProperties: false
PostApiV1AgentOutboundRequest:
type: object
properties:
xml:
type: string
idempotencyKey:
type: string
required:
- xml
- idempotencyKey
additionalProperties: false
PostApiV1BillingChangePackageRequest:
type: object
properties:
subscriptionTypeId:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- subscriptionTypeId
additionalProperties: false
PostApiV1BillingConfirmSetupRequest:
type: object
properties:
setupIntentId:
type: string
minLength: 1
required:
- setupIntentId
additionalProperties: false
PostApiV1IntegrationParticipantsCheckBatchRequest:
type: object
properties:
participants:
type: array
items:
type: string
documentTypeId:
type: string
format:
type: string
enum:
- json
- text
required:
- participants
additionalProperties: false
PostApiV1InvoicesOutboundRequest:
type: object
properties:
xml:
type: string
description: base64-encoded invoice XML, or multipart file
required:
- xml
additionalProperties: false
PatchApiV1InvoicesOutboundIdRequest:
type: object
properties:
action:
type: string
const: revalidate
required:
- action
additionalProperties: false
PostApiV1InvoicesOutboundIdTddAbandonRequest:
type: object
properties:
reason:
type: string
minLength: 1
maxLength: 500
required:
- reason
additionalProperties: false
PostApiV1InvoicesOutboundIdTddReopenRequest:
type: object
properties:
reason:
type: string
minLength: 1
maxLength: 500
required:
- reason
additionalProperties: false
PostApiV1OrgIntegrationKeysRequest:
type: object
properties:
label:
type: string
scopes:
type: array
items:
type: string
required:
- label
- scopes
additionalProperties: false
PatchApiV1OrgUsersIdRequest:
type: object
properties:
fullName:
anyOf:
- type: string
maxLength: 200
- type: "null"
phone:
anyOf:
- type: string
maxLength: 30
- type: "null"
roleId:
anyOf:
- type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- type: "null"
additionalProperties: false
PostApiV1OrgUsersInviteRequest:
type: object
properties:
email:
type: string
format: email
pattern: ^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$
fullName:
type: string
maxLength: 200
roleId:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- email
- roleId
additionalProperties: false
PatchApiV1ProfileRequest:
type: object
properties:
fullName:
type: string
minLength: 1
maxLength: 200
phone:
type: string
maxLength: 30
required:
- fullName
additionalProperties: false
PostApiV1ProfilePasswordRequest:
type: object
properties:
currentPassword:
type: string
minLength: 1
newPassword:
type: string
minLength: 12
required:
- currentPassword
- newPassword
additionalProperties: false
PostApiV1SecurityCloseAccountCancelRequest:
type: object
properties: {}
additionalProperties: false
PostApiV1WebhooksInboundRequest:
type: object
properties:
transmissionId:
type: string
payloadRef:
type: string
payloadSha256:
type: string
documentTypeId:
type: string
processId:
type: string
receiptRef:
type: string
required:
- transmissionId
- payloadRef
- payloadSha256
additionalProperties: false
PostApiV1WebhooksSendStatusRequest:
type: object
properties:
documentId:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
status:
type: string
enum:
- accepted
- sent
- delivered
- rejected
receipt:
type: string
rejectReason:
anyOf:
- type: string
enum:
- RECEIVER_NOT_REGISTERED_IN_SMP
- DISCOVERY_FAILED
- type: "null"
required:
- status
additionalProperties: false
PostApiV1WebhooksStripeRequest:
type: object
properties:
id:
type: string
type:
type: string
livemode:
type: boolean
created:
type: number
data:
type: object
properties:
object:
type: object
propertyNames:
type: string
additionalProperties: {}
required:
- object
additionalProperties: false
required:
- id
- type
- livemode
- created
- data
additionalProperties: false
AdminAddParticipantIdentifierRequest:
type: object
properties:
p_tenant_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_scheme:
type: string
p_value:
type: string
required:
- p_tenant_id
- p_scheme
- p_value
additionalProperties: false
AdminCreateRoleRequest:
type: object
properties:
p_name:
type: string
p_description:
type: string
required:
- p_name
additionalProperties: false
AdminCreateSubscriptionTypeRequest:
type: object
properties:
p_name:
type: string
p_price:
type: number
p_currency:
type: string
p_interval:
type: string
required:
- p_name
- p_price
- p_currency
- p_interval
additionalProperties: false
AdminCreateTenantRequest:
type: object
properties:
p_name:
type: string
p_ico:
type: string
p_dic:
type: string
p_subscription_type_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_name
additionalProperties: false
AdminCreateValidationRuleVersionRequest:
type: object
properties:
p_rule_key:
type: string
p_schema_version:
type: string
p_valid_from:
type: string
p_note:
type: string
p_file_name:
type: string
p_sha256:
type: string
p_size_bytes:
type: number
p_sef_sha256:
type: string
p_sef_size_bytes:
type: number
required:
- p_rule_key
- p_schema_version
- p_valid_from
- p_file_name
- p_sha256
- p_size_bytes
- p_sef_sha256
- p_sef_size_bytes
additionalProperties: false
AdminDeleteHelpArticleRequest:
type: object
properties:
p_slug:
type: string
required:
- p_slug
additionalProperties: false
AdminDeleteHelpCategoryRequest:
type: object
properties:
p_code:
type: string
required:
- p_code
additionalProperties: false
AdminDeleteHelpFaqRequest:
type: object
properties:
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_id
additionalProperties: false
AdminDeleteKnowledgeArticleRequest:
type: object
properties:
p_code:
type: string
required:
- p_code
additionalProperties: false
AdminDeleteUiStringOverrideRequest:
type: object
properties:
p_key:
type: string
p_locale:
type: string
required:
- p_key
- p_locale
additionalProperties: false
AdminDeployValidationChangesRequest:
type: object
properties:
p_version_ids:
type: array
items:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_note:
type: string
additionalProperties: false
AdminDiscardValidationPendingRequest:
type: object
properties:
p_version_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_rule_key:
type: string
additionalProperties: false
AdminProvisionUserRequest:
type: object
properties:
p_auth_user_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_tenant_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_role_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_full_name:
type: string
required:
- p_auth_user_id
- p_tenant_id
- p_role_id
additionalProperties: false
AdminResetMfaRequest:
type: object
properties:
p_user_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_user_id
additionalProperties: false
AdminRevertValidationDeploymentRequest:
type: object
properties:
p_deployment_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_deployment_id
additionalProperties: false
AdminSetHelpArticleActiveRequest:
type: object
properties:
p_slug:
type: string
p_is_active:
type: boolean
required:
- p_slug
- p_is_active
additionalProperties: false
AdminSetHelpCategoryActiveRequest:
type: object
properties:
p_code:
type: string
p_is_active:
type: boolean
required:
- p_code
- p_is_active
additionalProperties: false
AdminSetHelpFaqActiveRequest:
type: object
properties:
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_is_active:
type: boolean
required:
- p_id
- p_is_active
additionalProperties: false
AdminSetKnowledgeArticleActiveRequest:
type: object
properties:
p_code:
type: string
p_is_active:
type: boolean
required:
- p_code
- p_is_active
additionalProperties: false
AdminSetParticipantIdentifierActiveRequest:
type: object
properties:
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_active:
type: boolean
required:
- p_id
- p_active
additionalProperties: false
AdminSetRoleActiveRequest:
type: object
properties:
p_role_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_active:
type: boolean
required:
- p_role_id
- p_active
additionalProperties: false
AdminSetRolePermissionsRequest:
type: object
properties:
p_role_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_permissions:
type: array
items:
type: object
properties:
resource:
type: string
level:
type: string
enum:
- none
- read
- read_write
required:
- resource
- level
additionalProperties: false
required:
- p_role_id
- p_permissions
additionalProperties: false
AdminSetSubscriptionTypeActiveRequest:
type: object
properties:
p_subscription_type_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_active:
type: boolean
required:
- p_subscription_type_id
- p_active
additionalProperties: false
AdminSetSubscriptionTypeFeaturesRequest:
type: object
properties:
p_subscription_type_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_features:
type: array
items:
type: string
required:
- p_subscription_type_id
- p_features
additionalProperties: false
AdminSetTenantStatusRequest:
type: object
properties:
p_tenant_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_status:
type: string
enum:
- active
- suspended
- closed
required:
- p_tenant_id
- p_status
additionalProperties: false
AdminSetUserStatusRequest:
type: object
properties:
p_user_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_status:
type: string
enum:
- active
- suspended
required:
- p_user_id
- p_status
additionalProperties: false
AdminSetValidationRuleActiveRequest:
type: object
properties:
p_rule_key:
type: string
p_active:
type: boolean
required:
- p_rule_key
- p_active
additionalProperties: false
AdminStageValidationConfigChangeRequest:
type: object
properties:
p_rule_key:
type: string
p_inbound:
type: boolean
p_outbound:
type: boolean
p_blocking:
type: boolean
required:
- p_rule_key
additionalProperties: false
AdminUpdateDocumentStateRequest:
type: object
properties:
p_code:
type: string
p_is_active:
type: boolean
p_severity:
type: string
p_color_ui:
type: string
p_label:
type: string
p_description:
type: string
p_locale:
default: sk
type: string
required:
- p_code
additionalProperties: false
AdminUpdateDocumentTypeRequest:
type: object
properties:
p_code:
type: string
p_is_enabled:
type: boolean
p_label:
type: string
p_description:
type: string
p_locale:
default: sk
type: string
required:
- p_code
additionalProperties: false
AdminUpdateRoleRequest:
type: object
properties:
p_role_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_name:
type: string
p_description:
type: string
required:
- p_role_id
additionalProperties: false
AdminUpdateSettingRequest:
type: object
properties:
p_key:
type: string
p_value:
anyOf:
- type: string
- type: "null"
required:
- p_key
- p_value
additionalProperties: false
AdminUpdateSubscriptionTypeRequest:
type: object
properties:
p_subscription_type_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_name:
type: string
p_price:
type: number
required:
- p_subscription_type_id
additionalProperties: false
AdminUpdateTenantRequest:
type: object
properties:
p_tenant_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_name:
type: string
p_ico:
type: string
p_dic:
type: string
p_subscription_type_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_tenant_id
additionalProperties: false
AdminUpdateUserRequest:
type: object
properties:
p_user_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_full_name:
type: string
p_role_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_user_id
additionalProperties: false
AdminUpsertHelpArticleRequest:
type: object
properties:
p_slug:
type: string
p_category_code:
type: string
p_sort_order:
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
p_is_active:
type: boolean
p_content:
type: object
propertyNames:
type: string
additionalProperties:
type: object
propertyNames:
type: string
additionalProperties:
type: string
required:
- p_slug
- p_category_code
- p_sort_order
- p_is_active
- p_content
additionalProperties: false
AdminUpsertHelpCategoryRequest:
type: object
properties:
p_code:
type: string
p_style:
type: string
p_sort_order:
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
p_is_active:
type: boolean
p_content:
type: object
propertyNames:
type: string
additionalProperties:
type: object
propertyNames:
type: string
additionalProperties:
type: string
required:
- p_code
- p_style
- p_sort_order
- p_is_active
- p_content
additionalProperties: false
AdminUpsertHelpFaqRequest:
type: object
properties:
p_id:
anyOf:
- type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- type: "null"
p_category_code:
type: string
p_sort_order:
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
p_is_active:
type: boolean
p_content:
type: object
propertyNames:
type: string
additionalProperties:
type: object
propertyNames:
type: string
additionalProperties:
type: string
required:
- p_id
- p_category_code
- p_sort_order
- p_is_active
- p_content
additionalProperties: false
AdminUpsertKnowledgeArticleRequest:
type: object
properties:
p_code:
type: string
p_sort_order:
type: integer
minimum: -9007199254740991
maximum: 9007199254740991
p_is_active:
type: boolean
p_content:
type: object
propertyNames:
type: string
additionalProperties:
type: object
propertyNames:
type: string
additionalProperties:
anyOf:
- type: string
- type: "null"
required:
- p_code
- p_sort_order
- p_is_active
- p_content
additionalProperties: false
AdminUpsertUiStringOverrideRequest:
type: object
properties:
p_key:
type: string
p_locale:
type: string
p_value:
type: string
required:
- p_key
- p_locale
- p_value
additionalProperties: false
DlqDiscardRequest:
type: object
properties:
p_kind:
type: string
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_kind
- p_id
additionalProperties: false
DlqRequeueRequest:
type: object
properties:
p_kind:
type: string
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_kind
- p_id
additionalProperties: false
GetOutboundDocumentAuditTrailRequest:
type: object
properties:
p_outbound_document_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_outbound_document_id
additionalProperties: false
InboundDeliveryReleaseRequest:
type: object
properties:
p_inbound_document_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_inbound_document_id
additionalProperties: false
LegalHoldPlaceRequest:
type: object
properties:
p_kind:
type: string
enum:
- outbound_document
- inbound_document
- tdd_document
- quarantine_item
- audit_log
- tenant
p_target_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_reason:
type: string
p_owner:
type: string
required:
- p_kind
- p_target_id
- p_reason
- p_owner
additionalProperties: false
LegalHoldReleaseRequest:
type: object
properties:
p_hold_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_release_reason:
type: string
required:
- p_hold_id
- p_release_reason
additionalProperties: false
LegalHoldReportRequest:
type: object
properties:
p_status:
type: string
enum:
- active
- released
additionalProperties: false
LogAdminSessionBanRequest:
type: object
properties:
p_target_user_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_action:
type: string
enum:
- ban
- unban
required:
- p_target_user_id
- p_action
additionalProperties: false
NotifyAccountSecurityEventRequest:
type: object
properties:
p_user_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_template_key:
type: string
required:
- p_user_id
- p_template_key
additionalProperties: false
OrgAddParticipantIdentifierRequest:
type: object
properties:
p_scheme:
type: string
p_value:
type: string
required:
- p_scheme
- p_value
additionalProperties: false
OrgCloseUserAccountRequest:
type: object
properties:
p_user:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_user
additionalProperties: false
OrgCreateIntegrationKeyRequest:
type: object
properties:
p_label:
type: string
p_key_hash:
type: string
p_key_prefix:
type: string
p_scopes:
type: array
items:
type: string
required:
- p_label
- p_key_hash
- p_key_prefix
- p_scopes
additionalProperties: false
OrgListIntegrationKeysRequest:
type: object
properties: {}
additionalProperties: false
OrgProvisionUserRequest:
type: object
properties:
p_auth_user_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_role_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_full_name:
type: string
required:
- p_auth_user_id
- p_role_id
additionalProperties: false
OrgRecordUserPhoneChangeRequest:
type: object
properties:
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_old_phone:
anyOf:
- type: string
- type: "null"
p_new_phone:
anyOf:
- type: string
- type: "null"
required:
- p_id
- p_old_phone
- p_new_phone
additionalProperties: false
OrgResetMfaRequest:
type: object
properties:
p_user:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_user
additionalProperties: false
OrgRevokeIntegrationKeyRequest:
type: object
properties:
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_id
additionalProperties: false
OrgSetParticipantIdentifierActiveRequest:
type: object
properties:
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_active:
type: boolean
required:
- p_id
- p_active
additionalProperties: false
OrgSetUserStatusRequest:
type: object
properties:
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_status:
type: string
enum:
- invited
- active
- suspended
- disabled
required:
- p_id
- p_status
additionalProperties: false
OrgUpdateDetailsRequest:
type: object
properties:
p_name:
type: string
p_ico:
anyOf:
- type: string
- type: "null"
p_dic:
anyOf:
- type: string
- type: "null"
p_ic_dph:
anyOf:
- type: string
- type: "null"
p_address_street:
anyOf:
- type: string
- type: "null"
p_address_city:
anyOf:
- type: string
- type: "null"
p_address_postal_code:
anyOf:
- type: string
- type: "null"
p_address_country_code:
anyOf:
- type: string
- type: "null"
required:
- p_name
- p_ico
- p_dic
- p_ic_dph
- p_address_street
- p_address_city
- p_address_postal_code
- p_address_country_code
additionalProperties: false
OrgUpdateUserRequest:
type: object
properties:
p_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
p_full_name:
anyOf:
- type: string
- type: "null"
p_role_id:
anyOf:
- type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
- type: "null"
required:
- p_id
- p_full_name
- p_role_id
additionalProperties: false
ProfileRecordPhoneChangeRequest:
type: object
properties:
p_old:
anyOf:
- type: string
- type: "null"
p_new:
anyOf:
- type: string
- type: "null"
required:
- p_old
- p_new
additionalProperties: false
ProfileUpdateSelfRequest:
type: object
properties:
p_full_name:
type: string
required:
- p_full_name
additionalProperties: false
RecordAuthEventRequest:
type: object
properties:
p_event:
type: string
enum:
- logout
- mfa_enrolled
- mfa_failed
- password_changed
required:
- p_event
additionalProperties: false
RequeueInboundDeliveryRequest:
type: object
properties:
p_inbound_document_id:
type: string
format: uuid
pattern: ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$
required:
- p_inbound_document_id
additionalProperties: false
responses:
ApiError:
description: "Standard error shape (SEC-6 / CQ-2): `{ error, correlationId }`."
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
securitySchemes:
sessionCookie:
type: apiKey
in: cookie
name: sb-<project-ref>-auth-token
description: "The developer's own same-origin Supabase AAL2 session cookie (name
is project-ref-derived by `@supabase/ssr`, and may be chunked
`.0`/`.1`). Swagger UI \"Try it out\" sends it automatically
same-origin; it is not entered manually. service-auth (webhooks, HMAC)
and agent-auth (agent M2M, api-key/mTLS) operations have no browser
session credential — they are documented (`x-auth-kind`) but
non-executable (`x-try-it-out: false`)."
hmacSignature:
type: apiKey
in: header
name: X-Signature
description: Service auth for the Adapter→portal webhooks (`webhooks` tag).
Lowercase-hex HMAC-SHA-256 over the body-binding canonical string
`POST\n<path>\n\n<X-Timestamp>\n<sha256hex(rawBody)>`
(lib/adapter/webhook-hmac.ts; the send-status route uses its own path +
the `ADAPTER_SEND_STATUS_SECRET` secret). MUST be sent with the
`X-Timestamp` header (documented as an explicit request header; ±300s
replay window). Not exercisable from a browser.
agentAuth:
type: apiKey
in: header
name: X-Agent-Key
description: "Machine-to-machine agent auth for the `agent-m2m` tag
(lib/agent-auth/verify-agent.ts). Dev/default `api_key` mode: the hashed
key in `X-Agent-Key: <key>` (or, equivalently, `Authorization: Bearer
<key>`) resolves to exactly one active agent principal. Production
`mtls` mode instead uses a proxy-terminated client certificate — the
terminating proxy forwards the identity in `X-Client-Cert-SPKI-SHA256`
and proves its own provenance with `X-Proxy-Auth`; the app never trusts
the cert header from an untrusted path. Not exercisable from a browser."
integrationKeyAuth:
type: http
scheme: bearer
description: "Tenant integration-key auth for the public Integration API (Plan
207; lib/integration-auth/verify-integration-key.ts). A tenant admin
generates a scoped, hashed, revocable key (`gdl_int_<...>`) and the
accounting program sends it as `Authorization: Bearer <key>` OR
`X-Integration-Key: <key>`. NOT a browser session and NOT the agent M2M
credential (this is a plain API key — no mTLS mode). It carries no RBAC
role and resolves strictly to its own scopes (lookup:single /
lookup:bulk). Not exercisable from a browser session (x-try-it-out:
false)."
security:
- sessionCookie: []