Connect signup and login verification to email notifications #39

Merged
tech merged 12 commits from auth-38 into main 2026-09-12 17:46:16 +00:00
556 changed files with 42291 additions and 777 deletions
Showing only changes of commit 7062672a87 - Show all commits

No files matched your search

@@ -0,0 +1,59 @@
---
name: review-backend-change
description: Review, fix, and validate the complete SXCHNGE backend contribution for a task. Use before reporting completion whenever Go, protobuf, or other backend code under backend/ was added or modified, or when the user requests a backend implementation review.
---
# Review Backend Change
## Establish the review scope
1. Read the repository root `AGENTS.md` and `backend/AGENTS.md` completely.
2. Inspect repository status and the full backend diff attributable to the
current task, including uncommitted and committed changes against the task's
base.
3. Separate unrelated pre-existing work from the task contribution. Preserve
it and do not include it in review fixes.
4. Identify changed behavior, public or internal contracts, and expected test
coverage before judging individual lines.
## Review and fix the contribution
1. Apply every quality requirement in `backend/AGENTS.md` to the entire task diff,
not only the most recently edited file.
2. Search the repository for canonical protobuf messages, enums, Go types,
interfaces, and shared domain definitions before accepting new ones.
3. Check project-error usage, cause preservation, cohesion, naming, API and
module boundaries, duplication, dead code, and testability.
4. Review structured logging at meaningful operational and domain boundaries.
Check level selection, context, sensitive-data handling, and duplicate error
logging.
5. Review success, edge, and failure paths. Add or update focused tests for the
changed behavior.
6. Fix every in-scope issue found, then re-read the resulting complete backend
diff. Repeat until no task-caused finding remains.
Do not weaken checks, suppress failures, or modify unrelated user work to make
validation pass.
## Validate
After review fixes are complete, run these commands from the repository root:
```text
make test
make lint-backend
```
Then select and run every applicable security command from the change-scoped
security completion requirements in the root `AGENTS.md`.
All commands must succeed before reporting the backend task as complete. If a
command fails, determine whether the task caused it and fix in-scope failures.
Report an external or environmental blocker with the exact command and failure;
never represent blocked validation as successful.
## Report the result
Summarize the reviewed backend scope, material fixes made during review, tests
added or updated, and the outcome of each required command. Call out contract,
migration, rollout, security, or observability implications that remain relevant.
+4
View File
@@ -25,3 +25,7 @@ pnpm-debug.log*
# Local editor configuration
/.vscode/
# Local BFF configuration and build output
/backend/config.yml
/backend/bff
+2 -2
View File
@@ -74,8 +74,8 @@ repository changes do not require a branch.
## Scoped implementation requirements
- For backend code under `api/`, read and follow
[`api/AGENTS.md`](api/AGENTS.md). Before reporting completion, use the
- For backend code under `backend/`, read and follow
[`backend/AGENTS.md`](backend/AGENTS.md). Before reporting completion, use the
[`$review-backend-change`](.agents/skills/review-backend-change/SKILL.md)
skill.
- For Dart or Flutter code under `frontend/`, read and follow
+5
View File
@@ -1,3 +1,7 @@
.PHONY: test
test: test-backend test-frontend
.PHONY: test-frontend
test-frontend:
@@ -15,6 +19,7 @@ test-backend:
cd backend && go test -race ./...
lint-backend:
cd backend && go test ./internal/architecture
cd backend && test -z "$$(gofmt -l .)"
cd backend && go vet ./...
+15 -11
View File
@@ -1,7 +1,7 @@
# SXCHNGE
Product repository for the sxchnge public website, Flutter consumer app, reusable
packages, and planned backend for frontend (BFF).
packages, and a backend for frontend (BFF) bootstrapped from Sendico.
## Current state
@@ -11,9 +11,9 @@ with `go_router`. Its interface uses the shared theme's colors and typography.
**Authentication, email verification and analytics use dummy services.** No real
account or session is created, no email is delivered, and no analytics data is
transmitted. The backend has an independent Go operational shell; product services
are not connected. Session/KYC access guards and Sendico integration are not
implemented.
transmitted by those app services. The backend now contains locally owned copies
of Sendico’s BFF runtime, auth/session stack and account service. The app is not
connected to that backend or to Sendico yet.
## Repository structure
@@ -24,7 +24,7 @@ implemented.
| [`sxchnge_theme`](frontend/packages/sxchnge_theme/README.md) | Reusable light/dark themes and bundled Onest font |
| [`sxchnge_auth`](frontend/packages/sxchnge_auth/README.md) | Shared auth contracts, providers, two-factor page and dummy services |
| [`sxchnge_analytics`](frontend/packages/sxchnge_analytics/README.md) | Typed journey events, recorder and bounded in-memory dummy analytics |
| [`backend/`](backend/README.md) | Independent Go BFF starter, adapted foundations and provider integration plan |
| [`backend/`](backend/README.md) | Copied BFF/auth/account foundation and isolated public Sendico contracts |
| [`.agents/skills/`](.agents/skills) | Repository agent skills |
| [`docs/`](docs/implementation.md) | Implementation records and UX measurement contracts |
@@ -144,17 +144,19 @@ usability, accessibility and journey measurement under the repository's UX rules
## Product boundaries
The intended integration is: **consumer app → sxchnge BFF → supported Sendico API**.
The integration is: **consumer app → sxchnge BFF → Sendico public HTTP API**.
SXCHNGE is one organization in Sendico; its customers are owned locally.
- sxchnge will own consumer registration/sessions, onboarding and exchange UX,
and mappings to stable, organization-scoped Sendico customer references.
and mappings from local customers to organization-scoped platform resources.
- Sendico remains authoritative for payment execution, KYC records and
verification, policy decisions and limit enforcement.
- The sxchnge organization, backend integration principal and individual customer
references are distinct identities. Consumers must not share the integration
account's customer identity.
- The BFF uses a supported provider API. Selected Sendico components may be
adapted into SXCHNGE-owned code; local Sendico module dependencies are not used.
- The BFF uses only the public HTTP API. Existing BFF/auth/account components
are copied into SXCHNGE-owned code; private transports and sibling module
dependencies are not used.
Integration credentials belong in the backend.
Before backend integration, agree on the customer, KYC, eligibility/limits and
@@ -234,5 +236,7 @@ gaps and delivery phases. Selected Sendico code has been adapted with recorded
[provenance](backend/PROVENANCE.md); the projects share no runtime modules.
Run `make test-backend`, `make lint-backend` or `make run-backend` from the root.
The starter exposes health and unconfigured readiness only. Authentication,
persistence and live financial operations remain the next implementation phases.
The copied runtime installs local authentication transport and initializes its
account service. Signup/profile endpoints, verification delivery/completion,
Flutter HTTP adapters and live Sendico operations remain to be wired. See the
[backend run guide](backend/README.md) for local MongoDB configuration.
+92 -12
View File
@@ -1,15 +1,95 @@
# BFF guidelines
# Backend Agent Guidelines
Follow root AGENTS.md. This is an independent Go module; Sendico is an external
provider, not a local module dependency. Never add sibling-path replacements,
shared database access or internal Sendico discovery/messaging dependencies.
These instructions extend the repository-wide rules in the root `AGENTS.md`
and apply whenever a task adds or modifies backend code, including Go and
protobuf files under `backend/`.
Keep HTTP DTOs/mappers, application models/use cases and provider adapters distinct.
Resolve ownership from the authenticated SXCHNGE principal and server-side mappings.
Only adapters may expose provider transport types internally. Adapted code belongs
to SXCHNGE; record source revision and changes in PROVENANCE.md.
Before completing the task, review the entire backend diff produced by the
current task, fix every in-scope issue found, and then perform the required
validation. Use the
[`$review-backend-change`](../.agents/skills/review-backend-change/SKILL.md)
skill to perform this completion workflow.
Review the complete backend contribution before delivery. Run `make test-backend`
and `make lint-backend` at the repository root. Add behavioral tests for changed
boundaries and failure paths. Errors returned publicly must be stable typed codes;
never expose raw provider errors, secrets, document contents or credentials.
## Reuse existing definitions
- Search the repository before introducing a protobuf message, enum, Go struct,
interface, or shared domain type.
- Reuse or extend the canonical existing definition when its semantics match.
Do not create parallel representations or conversion layers for the same
concept without a clear architectural reason.
- Avoid naming stutter in packages, types, fields, parameters, and access paths.
Each nested name should add meaning instead of repeating its parent context.
For example, prefer a concise path such as `payment.Details.ID` over
`payment.Payment.PaymentID`.
## Use the project error model
- Do not introduce `fmt.Errorf` or `errors.New`. Use the constructors and
wrapping helpers in `backend/pkg/merrors`.
- Preserve the underlying cause when adding context by using an appropriate
`merrors` wrapping helper.
- When no suitable project error exists, add the smallest generally useful
definition or helper to `backend/pkg/merrors` instead of creating an ad hoc error
elsewhere.
## Keep modules cohesive and names concise
- Review touched files for excessive size, mixed responsibilities, duplicated
logic, and poor separation of concerns.
- Refactor oversized contributions into focused, cohesive files or packages.
Do not split code mechanically; organize it along clear domain or
architectural boundaries.
- Avoid repeating directory or package context in child directory and file
names. For example, prefer `payment/widget.dart` over
`payment/payment_widget.dart`.
## Review implementation quality
- Review the current task's backend contribution for correctness, readability,
maintainability, testability, and consistency with the surrounding
architecture.
- Keep public APIs and module boundaries small and intentional. Remove
unnecessary indirection, duplication, dead code, and speculative abstractions.
- Add or update tests for changed behavior, edge cases, and failure paths.
- Fix all findings caused by the current task before reporting completion.
## Review logging
- Ensure the contribution has sufficient structured logging at meaningful
operational and domain boundaries. Include useful identifiers and context,
but never log credentials, secrets, or sensitive payment data.
- Follow the repository's logging style and use levels consistently:
- `Debug`: fine-grained runtime execution tracking useful during debugging.
- `Info`: important payment-domain events, module-boundary operations,
effective module configuration, and noteworthy but expected deviations from
the usual path.
- `Warn`: runtime errors and unexpected conditions from which the service can
continue or which are returned to a caller.
- `Error`: unrecoverable failures that cause, or imminently lead to, service
or component termination.
- Avoid logging the same error repeatedly at multiple layers. Log it where the
layer has enough context to make the event actionable.
## Required validation
- From the repository root, run `make test` and `make lint-backend`, plus every
applicable command from the root `AGENTS.md` change-scoped security
requirements, after all review fixes are complete.
- All commands must succeed before the task is reported as complete. Fix
failures introduced by the current task; do not silently skip, suppress, or
weaken checks.
- Report the commands run and their outcomes in the final response. If an
external or environmental blocker prevents a command from running, report
the exact command, failure, and blocker explicitly; do not claim successful
validation.
## SXCHNGE provider boundary
SXCHNGE owns auth, sessions and customer management. SXCHNGE is one organization
inside Sendico. Copied BFF components are locally owned and may diverge.
Use only Sendico's public HTTP API for platform operations. Never import sibling
Sendico modules or access its database, internal gRPC APIs, discovery or message
bus. Keep the pinned public wire contract separate from local DTOs and models.
Resolve the configured provider organization and customer resource ownership on
the server. Never treat all customers as the backend integration principal.
Use the copied structured logger, injected at operational boundaries.
File diff suppressed because it is too large. Load diff
+54 -28
View File
@@ -1,38 +1,64 @@
# Sendico reuse provenance
# Copied Sendico source
Source repository: `S_I/sendico`; revision `8bb20dcd622dd8eb92d289b6b34411e7eccab083`.
Inspected 2026-09-12. These are owned forks inside SXCHNGE, not runtime imports.
Source files below match the committed revision; local dependency edits were not used.
No generated Sendico SDK, shared database models, deployment configuration or credentials were copied.
Source repository: `S_I/sendico` (`git.sendico.io`). Revision:
`8bb20dcd622dd8eb92d289b6b34411e7eccab083`.
## `internal/browser/policy.go`
[PROVENANCE.json](PROVENANCE.json) records each copied file, original path and
Git blob, plus whether a Go file changed beyond import namespace and formatting.
It contains 416 Go source/test files, 112 public OpenAPI files and one adapted policy seed. Sources were
read from the pinned commit, not Sendico's dirty working tree. These are owned
SXCHNGE copies, not submodules or automatic synchronization links.
- Source: [api/edge/shared/auth/browser/browser.go](https://git.sendico.io/S_I/sendico/src/commit/8bb20dcd622dd8eb92d289b6b34411e7eccab083/api/edge/shared/auth/browser/browser.go)
- Source Git blob: `3af7b54aea277d91e0d8c3eba9ee84c155f4b624`
- Adaptation: Adapted cookie creation/clearing, origin validation and CSRF checks. Replaced Sendico names/errors/env path resolution with explicit SXCHNGE policy; checks do not depend on a client-controlled transport header. Host-only Secure/HttpOnly cookie, Lax same-site navigation, duplicate-cookie rejection and explicit expiry validation.
- Tests are SXCHNGE-specific behavioral checks for the adapted boundary.
## What was retained
## `internal/credential/token.go`
- Shared BFF Chi runtime, process/version/logger bootstrap, HTTP middleware,
auth transport and response conventions.
- Password/account service, local Mongo account/role/policy repositories,
transactions and local organization membership.
- Verification issuance, expiry, attempt limits, consumption and idempotency;
refresh-session rotation/revocation and login rate-limit storage.
- Canonical models, `merrors`, structured logging, health and retained tests.
- The public OpenAPI 4.2.37 entry point and recursive local schema references,
copied into `contracts/sendico` without schema changes (trailing blank lines
normalized in three YAML files).
- Source: [api/edge/shared/storage/verification/hash.go](https://git.sendico.io/S_I/sendico/src/commit/8bb20dcd622dd8eb92d289b6b34411e7eccab083/api/edge/shared/storage/verification/hash.go)
- Source Git blob: `36fadcf404bfc77608b28cca1e669a4a62f31774`
- Adaptation: Adapted generateMagic/tokenHash only: 32-byte crypto/rand, URL-safe encoding, SHA-256 digest. Added constant-time matching. Excluded deterministic token generation, Sendico models and all numeric OTP hashing.
- Tests are SXCHNGE-specific behavioral checks for the adapted boundary.
## Deliberate adaptations
## `internal/evidence/key.go`
- Import roots now belong to `git.sendico.io/tech/sxchnge/bff`. Versions are seeded
from committed Sendico manifests and tidied for the selected dependency set.
- Product's composition root selects local account services instead of platform
services/provisioning. Its shared HTTP runtime remains the implementation.
- Removed internal discovery and broker configuration, registration, startup and
teardown. An instance ID uses the existing UUID dependency without discovery.
- Excluded internal gRPC/protobuf clients/converters and unused model files.
Local account-role values remain; private protobuf conversion helpers do not.
- Program identity and the refresh-cookie name use SXCHNGE.
- The policy seed retains the existing upsert helpers and three local
organization/account/role definitions, with an SXCHNGE database default.
Platform policies, automatic role backfills and pruning are excluded.
- Startup configuration now rejects missing database/middleware/HTTP settings
and invalid HTTP timeouts. Runtime-construction failure closes the database.
Listen/start failures preserve the cause and produce a nonzero CLI exit.
- Copied Casbin adapter errors and test sentinel errors use canonical `merrors`
instead of `errors.New`. Removed raw database settings from error logs.
- The recipient-migration-only test was excluded together with its migration:
neither that platform feature nor historical Sendico data migration is part of
this bootstrap. Tests for every retained runtime/component remain included.
- Source: [api/edge/shared/storage/s3key/key.go](https://git.sendico.io/S_I/sendico/src/commit/8bb20dcd622dd8eb92d289b6b34411e7eccab083/api/edge/shared/storage/s3key/key.go)
- Source Git blob: `e3cca16304d2c4cb9f256f510d5a1a30a21e22a6`
- Adaptation: Adapted relative object-key confinement. Replaced merrors with a local sentinel and rejected encoded sequences, backslashes and embedded control characters. Not a filesystem or customer-authorization utility.
- Tests are SXCHNGE-specific behavioral checks for the adapted boundary.
No financial engine, internal service client, gateway, platform organization
provisioning, deployment configuration, credential or generated binary was copied.
The local account service's organization is an SXCHNGE authorization tenant;
it does not create Sendico organizations per customer.
## Maintenance
## Local additions
The command, operational HTTP shell, module configuration and tests are new SXCHNGE code.
There is no automatic synchronization or promise of source compatibility with Sendico.
For an upstream fix, review the pinned source difference, port only the relevant behavior,
record a new provenance entry and run backend tests/vet. Provider contract changes belong
in the future Sendico adapter and its transport fixtures, not application models or widgets.
`internal/profile` composes the copied account service. Architecture checks enforce
project errors, no private provider imports/transports and self-contained public
contract references. Configuration tests cover the executable example and missing
settings. Guidelines and the backend-review skill are restored from Sendico with
SXCHNGE paths and the public-only integration boundary.
These primitives do not create sessions, deliver email, validate TOTP or upload documents.
Use them inside the durable flows described in the [BFF plan](../docs/architecture/bff.md).
The source includes complete local auth building blocks, not a fully wired
SXCHNGE product API. Remaining endpoint, email, local tenant/client provisioning
and public Sendico integration work is explicit in the
[architecture plan](../docs/architecture/bff.md).
+35 -27
View File
@@ -1,38 +1,46 @@
# SXCHNGE BFF
Independent Go module with an operational HTTP shell and selected, adapted
Sendico foundations. Sendico remains an external financial-services provider;
there are no Sendico module imports, shared databases or sibling-path dependencies.
See the [architecture and service plan](../docs/architecture/bff.md) and
[reuse provenance](PROVENANCE.md).
A locally owned copy of Sendico's reusable BFF runtime, authentication/session
stack and account service. See [provenance](PROVENANCE.md) and the
[architecture and public API plan](../docs/architecture/bff.md).
## Run and validate
SXCHNGE owns its customers and authentication. SXCHNGE itself is one organization
in Sendico. Provider integration uses only Sendico's public HTTP API; the pinned
[OpenAPI snapshot](contracts/sendico/api.yaml) is isolated from local models.
Requires Go 1.26 or later. From the repository root:
## Run locally
Requires Go 1.27 and an SXCHNGE-owned MongoDB replica set for transactions.
Copy `config.example.yml` to an untracked `config.yml`. Set:
- `SXCHNGE_MONGO_URI`: URI for the local SXCHNGE database.
- `SXCHNGE_JWT_SECRET`: private random signing key, at least 32 bytes for HS256.
- `SXCHNGE_DOMAIN`: local API hostname (for example `localhost:8082`).
- `SXCHNGE_API_PROTOCOL`: `http` locally, `https` in deployment.
- `SXCHNGE_API_ENDPOINT`: `/api/v1`.
Seed the local policy descriptions before first startup (requires `mongosh`):
```sh
make test-backend
make lint-backend
make run-backend
mongosh "$SXCHNGE_MONGO_URI" --file backend/scripts/seed-policies.js
```
The default address is `127.0.0.1:8082`; override with `SXCHNGE_HTTP_ADDR`.
`GET /healthz` reports process health. `GET /readyz` deliberately returns **503**
with `not_configured`: persistence, authentication and Sendico are not connected.
No product routes return dummy success. The process handles SIGINT/SIGTERM with
bounded graceful shutdown. Production transport must terminate HTTPS.
The seed is repeatable and creates only the three local built-in policy
descriptions required by the copied runtime. It grants no role permissions.
Run `make run-backend` from the repository root. The copied CLI accepts
`-config.file`, `-version` and `-debug`. Configure exact browser origins in YAML;
secure refresh cookies require HTTPS for browser session testing.
## Present components
The runtime mounts `/api/v1/health` and the copied account login, API login,
refresh, rotation and logout handlers. Customer/client records must exist in the
local database. The account service is initialized locally; signup/profile and
verification-delivery/completion routes are the next wiring work. This is a
bootstrap, not a finished authentication deployment. No Sendico calls are made.
- `cmd/bff`, `internal/httpapi`: HTTP process, timeouts and operational endpoints.
- `internal/browser`: explicit HTTPS origin/CSRF policy and Secure HttpOnly
host-only session cookie. Apply this policy to every future browser mutation;
it is not yet connected to product routes because those do not exist.
- `internal/credential`: random opaque credentials and storage digests. Never use
this helper for passwords or short OTP codes.
- `internal/evidence`: confined server-generated object keys; not a substitute
for ownership, upload validation or private storage controls.
## Validate
Only the standard library is required. Larger adapted flows, persistence,
provider DTOs/mappers, email and live integration follow the plan in separate
contributions. Source-derived components evolve independently inside this repo.
Run `make test` and `make lint-backend`. Backend tests include real MongoDB
integration tests through Testcontainers, so Docker must be running.
`make test-backend` runs the backend suite with the race detector.
Architecture checks reject private Sendico imports/transports and ad hoc error
constructors. The frontend still uses dummy services; no Flutter source changed.
+11 -36
View File
@@ -1,46 +1,21 @@
// Adapted from Sendico api/edge/product/main.go; see PROVENANCE.md.
package main
import (
"context"
"errors"
"log/slog"
"net/http"
"git.sendico.io/tech/sxchnge/bff/edge/shared/appversion"
"git.sendico.io/tech/sxchnge/bff/edge/shared/server"
"git.sendico.io/tech/sxchnge/bff/internal/profile"
"git.sendico.io/tech/sxchnge/bff/pkg/mlogger"
application "git.sendico.io/tech/sxchnge/bff/pkg/server"
smain "git.sendico.io/tech/sxchnge/bff/pkg/server/main"
"os"
"os/signal"
"syscall"
"time"
"git.sendico.io/tech/sxchnge/bff/internal/httpapi"
)
func factory(logger mlogger.Logger, file string, debug bool) (application.Application, error) {
return server.Create(logger, file, debug, profile.Runtime())
}
func main() {
if err := run(); err != nil {
slog.Error("BFF stopped", "error", err)
if smain.RunServer("sxchnge.bff", appversion.Create(), factory) != nil {
os.Exit(1)
}
}
func run() error {
addr := os.Getenv("SXCHNGE_HTTP_ADDR")
if addr == "" {
addr = "127.0.0.1:8082"
}
server := &http.Server{Addr: addr, Handler: httpapi.New(), ReadHeaderTimeout: 5 * time.Second, ReadTimeout: 15 * time.Second, WriteTimeout: 15 * time.Second, IdleTimeout: 60 * time.Second, MaxHeaderBytes: 1 << 20}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
failures := make(chan error, 1)
go func() { failures <- server.ListenAndServe() }()
slog.Info("BFF operational shell starting", "address", addr, "provider_configured", false)
select {
case err := <-failures:
if errors.Is(err, http.ErrServerClosed) {
return nil
}
return err
case <-ctx.Done():
shutdown, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
slog.Info("BFF shutting down")
return server.Shutdown(shutdown)
}
}
+35
View File
@@ -0,0 +1,35 @@
# SXCHNGE-owned Mongo database and JWT key. Never point these at Sendico.
http_server:
listen_address: 127.0.0.1:8082
read_header_timeout: 5
shutdown_timeout: 10
database:
driver: mongodb
settings:
uri_env: SXCHNGE_MONGO_URI
database: sxchnge
enforcer:
driver: native
api:
middleware:
domain_env: SXCHNGE_DOMAIN
api_endpoint_env: SXCHNGE_API_ENDPOINT
api_protocol_env: SXCHNGE_API_PROTOCOL
signature:
algorithm: HS256
secret_key_env: SXCHNGE_JWT_SECRET
CORS:
allowed_origins: ["http://localhost:5126"]
allowed_methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"]
allowed_headers: ["Content-Type", "Authorization", "X-Auth-Transport", "X-CSRF-Protection"]
allow_credentials: true
max_age: 300
token:
expiration_hours:
account: 1
refresh: 720
length: 32
password:
token_length: 32
check:
min_length: 12
+129
View File
@@ -0,0 +1,129 @@
openapi: 3.1.0
info:
title: Sendico API Contract
version: 4.2.37
summary: Minimal client contract for authenticated BFF flows.
description: |
OpenAPI 3.1 contract focused on authenticated client flows exposed by the BFF:
authentication, verification, recipients, payment methods, payments, wallets,
and ledger account history.
servers:
- url: /api/v1
description: Main HTTP API base path
tags:
- name: Auth
description: Authentication and token lifecycle
- name: Accounts
description: Account auth responses used by login/verification
- name: Verification
description: Pending-account code verification
- name: Organizations
description: Organization selection for payment operations
- name: Recipients
description: Recipient CRUD and archive flows
- name: Payment Methods
description: Payment method CRUD and archive flows
- name: Callbacks
description: Webhook callback subscription CRUD and signing material rotation for HMAC and detached-JWS callbacks
- name: Payments
description: Quotation and payment orchestration
- name: Wallets
description: Managed wallet metadata and balances
- name: Ledger Accounts
description: Ledger account balances and account-history operations
paths:
/accounts/login:
$ref: ./api/accounts/auth_login.yaml
/accounts/login/api:
$ref: ./api/accounts/auth_login_api.yaml
/accounts/rotate:
$ref: ./api/accounts/auth_rotate.yaml
/accounts/refresh:
$ref: ./api/accounts/auth_refresh.yaml
/verification:
$ref: ./api/verification/create.yaml
/verification/resend:
$ref: ./api/verification/resend.yaml
/verification/verify:
$ref: ./api/verification/verify.yaml
/organizations:
$ref: ./api/organizations/root.yaml
/organizations/{org_ref}:
$ref: ./api/organizations/get.yaml
/recipients/list/{org_ref}/{organizations_ref}:
$ref: ./api/recipients/list.yaml
/recipients/{org_ref}:
$ref: ./api/recipients/create.yaml
/recipients/{recipients_ref}:
$ref: ./api/recipients/object.yaml
/recipients:
$ref: ./api/recipients/update.yaml
/recipients/archive/{org_ref}/{recipients_ref}:
$ref: ./api/recipients/archive.yaml
/payment_methods/accounts/{organizations_ref}/{accounts_ref}:
$ref: ./api/payment_methods/accounts.yaml
/payment_methods/recipients/{organizations_ref}/{recipients_ref}:
$ref: ./api/payment_methods/recipients.yaml
/payment_methods/{organizations_ref}/{payment_methods_ref}:
$ref: ./api/payment_methods/object.yaml
/payment_methods/archive/{organizations_ref}/{payment_methods_ref}:
$ref: ./api/payment_methods/archive.yaml
/callbacks/list/{org_ref}/{organizations_ref}:
$ref: ./api/callbacks/list.yaml
/callbacks/{org_ref}:
$ref: ./api/callbacks/create.yaml
/callbacks/{callbacks_ref}:
$ref: ./api/callbacks/object.yaml
/callbacks:
$ref: ./api/callbacks/update.yaml
/callbacks/archive/{org_ref}/{callbacks_ref}:
$ref: ./api/callbacks/archive.yaml
/callbacks/rotate-secret/{callbacks_ref}:
$ref: ./api/callbacks/rotate_secret.yaml
/payments/quote/{organizations_ref}:
$ref: ./api/payments/quote.yaml
/payments/multiquote/{organizations_ref}:
$ref: ./api/payments/multiquote.yaml
/payments/immediate/{organizations_ref}:
$ref: ./api/payments/immediate.yaml
/payments/by-quote/{organizations_ref}:
$ref: ./api/payments/by_quote.yaml
/payments/by-multiquote/{organizations_ref}:
$ref: ./api/payments/by_multiquote.yaml
/payments/by-ref/{payments_ref}:
$ref: ./api/payments/object.yaml
/payments/{organizations_ref}:
$ref: ./api/payments/list.yaml
/payments/documents/certificate/{organizations_ref}:
$ref: ./api/payments/documents_certificate.yaml
/payments/registry/{organizations_ref}:
$ref: ./api/payments/registry.yaml
/payments/registry/refresh/{organizations_ref}:
$ref: ./api/payments/registry_refresh.yaml
/payments/fx/currencies/{organizations_ref}:
$ref: ./api/payments/fx_currencies.yaml
/payments/fx/directions/{organizations_ref}:
$ref: ./api/payments/fx_directions.yaml
/chain_wallets/{organizations_ref}/assets:
$ref: ./api/wallets/assets.yaml
/ledger_accounts/{organizations_ref}/{ledger_account_ref}/balance:
$ref: ./api/ledger_accounts/balance.yaml
/ledger_accounts/{organizations_ref}/{ledger_account_ref}/operations:
$ref: ./api/ledger_accounts/operations.yaml
/ledger_accounts/{organizations_ref}/{ledger_account_ref}/operations/{entry_ref}:
$ref: ./api/ledger_accounts/operation.yaml
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
@@ -0,0 +1,29 @@
post:
tags: [Accounts, Auth]
summary: Login using email/password and receive pending verification token
description: |
Validates account credentials and returns a short-lived `pendingToken`.
This endpoint does not return final access/refresh tokens; complete verification flow via `/verification/verify`.
operationId: accountsLogin
requestBody:
$ref: ./bodies/auth.yaml#/components/requestBodies/LoginBody
responses:
'202':
description: Pending verification token issued
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/auth.yaml#/components/schemas/PendingLoginData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,30 @@
post:
tags: [Accounts, Auth]
summary: API login using email/password and client credentials
description: |
Validates account credentials and eligible API client credentials, then returns final auth payload.
This endpoint bypasses login OTP/2FA and is intended only for approved API clients.
If the client definition includes `allowedCIDRs`, request source IP must match one of those CIDRs.
operationId: accountsApiLogin
requestBody:
$ref: ./bodies/auth.yaml#/components/requestBodies/ApiLoginBody
responses:
'200':
description: Login successful
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/auth.yaml#/components/schemas/LoginData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,31 @@
post:
tags: [Accounts, Auth]
summary: Refresh access token by refresh token
description: |
Validates refresh token + session identifiers and issues a new access token.
Use this endpoint when refresh token stays the same.
operationId: accountsRefreshAccessToken
requestBody:
$ref: ./bodies/auth.yaml#/components/requestBodies/RefreshTokenBody
responses:
'200':
description: Access token refreshed
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/auth.yaml#/components/schemas/AccountAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,31 @@
post:
tags: [Accounts, Auth]
summary: Rotate refresh token and issue new access/refresh tokens
description: |
Validates refresh token + session identifiers and returns a new token pair.
Use this endpoint when replacing both access and refresh tokens.
operationId: accountsRotateRefreshToken
requestBody:
$ref: ./bodies/auth.yaml#/components/requestBodies/RefreshTokenBody
responses:
'200':
description: New token pair issued
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/auth.yaml#/components/schemas/LoginData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,24 @@
components:
requestBodies:
LoginBody:
description: JSON credentials payload for standard login.
required: true
content:
application/json:
schema:
$ref: ../request/auth.yaml#/components/schemas/LoginRequest
ApiLoginBody:
description: JSON credentials payload for API client login.
required: true
content:
application/json:
schema:
$ref: ../request/auth.yaml#/components/schemas/ApiLoginRequest
RefreshTokenBody:
description: JSON payload containing session and refresh token data.
required: true
content:
application/json:
schema:
$ref: ../request/auth.yaml#/components/schemas/RefreshTokenRequest
@@ -0,0 +1,34 @@
components:
schemas:
LoginRequest:
type: object
additionalProperties: false
required:
- login
properties:
clientId:
type: string
description: Client identifier bound to refresh token lifecycle and client policy checks.
deviceId:
type: string
description: Device/server identifier associated with the client session.
login:
$ref: ../../../models/auth/login_data.yaml#/components/schemas/LoginData
ApiLoginRequest:
allOf:
- $ref: ./auth.yaml#/components/schemas/LoginRequest
- type: object
additionalProperties: false
required:
- clientId
- deviceId
- clientSecret
properties:
clientSecret:
type: string
format: password
description: Client secret for `client_secret_post` authentication.
RefreshTokenRequest:
$ref: ../../../models/auth/client_refresh_token.yaml#/components/schemas/ClientRefreshToken
@@ -0,0 +1,62 @@
components:
schemas:
AccountAuthData:
description: Authentication response containing account profile and access token.
type: object
additionalProperties: false
required:
- accessToken
- account
properties:
accessToken:
description: Access token used for authenticated requests.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
account:
description: Authenticated account data.
$ref: ../../../models/account/account.yaml#/components/schemas/AccountData
LoginData:
description: Full login response including access and refresh tokens.
type: object
additionalProperties: false
required:
- accessToken
- account
- refreshToken
properties:
accessToken:
description: Access token used for authenticated requests.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
account:
description: Authenticated account data.
$ref: ../../../models/account/account.yaml#/components/schemas/AccountData
refreshToken:
description: Refresh token used to obtain a new access token.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
PendingLoginData:
description: Pending login response requiring additional verification.
type: object
additionalProperties: false
required:
- account
- pendingToken
- target
properties:
account:
description: Interim authentication payload prepared for verification completion.
type: object
additionalProperties: false
properties:
accessToken:
description: Temporary access token issued before verification is completed.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
account:
description: Account data associated with the pending login flow.
$ref: ../../../models/account/account.yaml#/components/schemas/AccountData
pendingToken:
description: Token proving the pending verification session.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
target:
description: Verification target destination (for example email or phone).
type: string
@@ -0,0 +1,37 @@
get:
tags: [Callbacks]
summary: Archive/unarchive callback subscription
description: Sets callback archive state by `callbacks_ref` and required `archived` query parameter.
operationId: callbacksArchive
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/org_ref.yaml#/components/parameters/OrgRef
- $ref: ../parameters/callbacks_ref.yaml#/components/parameters/CallbacksRef
- name: archived
in: query
required: true
description: Target archive value to set on the callback.
schema:
type: boolean
- $ref: ../parameters/cascade.yaml#/components/parameters/Cascade
responses:
'200':
description: Archive state updated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/callback.yaml#/components/schemas/CallbacksAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,17 @@
components:
requestBodies:
CallbackCreateBody:
description: JSON body containing callback endpoint configuration for create.
required: true
content:
application/json:
schema:
$ref: ../request/callback.yaml#/components/schemas/CallbackCreateRequest
CallbackUpdateBody:
description: JSON body containing callback endpoint configuration for update.
required: true
content:
application/json:
schema:
$ref: ../request/callback.yaml#/components/schemas/CallbackUpdateRequest
@@ -0,0 +1,33 @@
post:
tags: [Callbacks]
summary: Create callback subscription
description: Creates callback subscription for the organization identified by `org_ref`.
operationId: callbacksCreate
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/org_ref.yaml#/components/parameters/OrgRef
requestBody:
$ref: ./bodies/callback.yaml#/components/requestBodies/CallbackCreateBody
responses:
'201':
description: Callback created
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/callback.yaml#/components/schemas/CallbacksAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'409':
$ref: ../response/operation.yaml#/components/responses/Conflict
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,35 @@
get:
tags: [Callbacks]
summary: List callback subscriptions
description: |
Lists callbacks for the given organization context.
The route currently includes both `org_ref` and `organizations_ref`; the handler resolves organization context from `org_ref` and ignores `organizations_ref`.
operationId: callbacksList
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/org_ref.yaml#/components/parameters/OrgRef
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/limit.yaml#/components/parameters/Limit
- $ref: ../parameters/offset.yaml#/components/parameters/Offset
- $ref: ../parameters/archived.yaml#/components/parameters/Archived
responses:
'200':
description: Callback list
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/callback.yaml#/components/schemas/CallbacksAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,64 @@
get:
tags: [Callbacks]
summary: Get callback subscription
description: Returns callback subscription by `callbacks_ref`.
operationId: callbacksGet
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/callbacks_ref.yaml#/components/parameters/CallbacksRef
responses:
'200':
description: Callback data
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/callback.yaml#/components/schemas/CallbacksAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
delete:
tags: [Callbacks]
summary: Delete callback subscription
description: Deletes callback by reference.
operationId: callbacksDelete
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/callbacks_ref.yaml#/components/parameters/CallbacksRef
- $ref: ../parameters/cascade.yaml#/components/parameters/Cascade
responses:
'200':
description: Callback deleted
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/callback.yaml#/components/schemas/CallbacksAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,113 @@
components:
schemas:
CallbackBackoffInput:
description: Optional retry backoff overrides. Non-positive values currently fall back to server defaults.
type: object
additionalProperties: false
properties:
minDelayMs:
type: integer
maxDelayMs:
type: integer
CallbackRetryPolicyInput:
description: Optional retry and signing overrides. Omitted or non-positive numeric values currently fall back to server defaults.
type: object
additionalProperties: false
properties:
backoff:
$ref: '#/components/schemas/CallbackBackoffInput'
signingMode:
description: |
Optional signing mode. Canonical values are documented here; current handler also accepts legacy aliases such as `hmac`, `hmac-sha256`, `jws-eddsa-ed25519`, `jws+eddsa-ed25519`, `jws_eddsa`, and `eddsa_ed25519`.
type: string
enum:
- none
- hmac_sha256
- jws_eddsa_ed25519
headers:
type: object
additionalProperties:
type: string
maxAttempts:
type: integer
requestTimeoutMs:
type: integer
CallbackCreateRequest:
description: |
Request payload used to create a callback configuration.
Only `url` is hard-required by current create logic. Other mutable fields are optional and defaulted by the handler when omitted.
type: object
additionalProperties: false
required:
- url
properties:
name:
description: Optional callback display name. When omitted, the handler defaults it to `url`.
type: string
description:
description: Optional callback description.
type: string
nullable: true
status:
description: |
Optional callback status. Canonical values are documented here; current handler also accepts `enabled` and `inactive` aliases.
type: string
enum:
- active
- disabled
url:
description: Absolute HTTPS callback endpoint URL.
type: string
format: uri
eventTypes:
description: Optional callback event types. When omitted or empty, the handler defaults this list.
type: array
items:
type: string
retryPolicy:
$ref: '#/components/schemas/CallbackRetryPolicyInput'
CallbackUpdateRequest:
description: |
Request payload used to update a callback configuration.
The current PUT handler requires `id`, `organizationRef`, and `url`. Other mutable fields are optional, but omitted values may be reset to handler defaults during normalization.
type: object
additionalProperties: false
required:
- id
- organizationRef
- url
properties:
id:
description: Callback identifier to update.
$ref: ../../../models/objectid.yaml#/components/schemas/ObjectId
organizationRef:
description: Organization identifier carried in the stored callback record and currently required by the update path.
$ref: ../../../models/objectid.yaml#/components/schemas/ObjectId
name:
description: Optional callback display name. When omitted, the handler defaults it to `url`.
type: string
description:
description: Optional callback description.
type: string
nullable: true
status:
description: |
Optional callback status. Canonical values are documented here; current handler also accepts `enabled` and `inactive` aliases.
type: string
enum:
- active
- disabled
url:
description: Absolute HTTPS callback endpoint URL.
type: string
format: uri
eventTypes:
description: Optional callback event types. When omitted or empty, the handler defaults this list.
type: array
items:
type: string
retryPolicy:
$ref: '#/components/schemas/CallbackRetryPolicyInput'
@@ -0,0 +1,22 @@
components:
schemas:
CallbacksAuthData:
description: Authenticated response payload containing callback configurations.
type: object
additionalProperties: false
required:
- accessToken
- callbacks
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
callbacks:
description: Collection of callbacks configured for the authenticated scope. JWS-signed callbacks expose read-only verification JWKs via `callbacks[].signingKeys`.
type: array
items:
$ref: ../../../models/callback/callback.yaml#/components/schemas/Callback
generatedSigningSecret:
description: Newly generated signing secret when HMAC signing material is created or rotated. JWS-signed callbacks do not populate this field.
type: string
nullable: true
@@ -0,0 +1,31 @@
post:
tags: [Callbacks]
summary: Rotate callback signing material
description: Rotates the active signing material for the callback. HMAC callbacks generate and return a new shared secret once. `jws_eddsa_ed25519` callbacks generate a new Ed25519 keypair, expose the new active verification JWK on normal callback reads, and keep retiring verification keys visible for 24 hours.
operationId: callbacksRotateSecret
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/callbacks_ref.yaml#/components/parameters/CallbacksRef
responses:
'200':
description: Callback signing material rotated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/callback.yaml#/components/schemas/CallbacksAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,31 @@
put:
tags: [Callbacks]
summary: Update callback subscription
description: Updates callback subscription fields. The current handler requires `id`, `organizationRef`, and `url`; omitted mutable fields may be reset to defaults.
operationId: callbacksUpdate
security:
- bearerAuth: []
requestBody:
$ref: ./bodies/callback.yaml#/components/requestBodies/CallbackUpdateBody
responses:
'200':
description: Callback updated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/callback.yaml#/components/schemas/CallbacksAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,58 @@
get:
tags: [Ledger Accounts]
summary: Get ledger account balance
description: |
Returns the canonical balance for the requested ledger account.
Without `as_of`, the response is the current materialized balance and includes
current metadata fields `version` and `lastUpdated`.
With `as_of`, the response is an event-time accounting balance reconstructed
from posted statement-entry deltas where `eventTime <= as_of`. Entries exactly
equal to `as_of` are included. This is not a historical snapshot of materialized
balance state and not "what the system knew" at that clock time. Late or
backdated postings with older `eventTime` can change historical responses for
the same `as_of`. Historical responses include `ledgerAccountRef`, `balance`,
and canonical UTC `asOf`, and omit `version` and `lastUpdated` because no
historical snapshot/version semantics are defined.
Historical balance is valid only if every account-affecting committed posting
writes matching statement entries in the same transaction as balance updates.
operationId: ledgerAccountBalanceGet
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/ledger_account_ref.yaml#/components/parameters/LedgerAccountRef
- name: as_of
in: query
required: false
description: |
Optional RFC3339 event-time cutoff for historical balance reconstruction.
Timezone offsets are accepted and returned as canonical UTC `asOf`.
schema:
type: string
format: date-time
example: '2026-04-23T14:30:00+02:00'
responses:
'200':
description: Ledger account balance
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/balance.yaml#/components/schemas/LedgerAccountBalanceData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,36 @@
get:
tags: [Ledger Accounts]
summary: Get ledger account operation detail
description: |
Returns the account-history projection for `entry_ref` within the requested ledger account.
This is not a general journal-entry read API.
The endpoint returns `404` when the entry is not part of the requested account's visible history.
operationId: ledgerAccountOperationsGet
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/ledger_account_ref.yaml#/components/parameters/LedgerAccountRef
- $ref: ../parameters/entry_ref.yaml#/components/parameters/EntryRef
responses:
'200':
description: Ledger account operation detail
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/operation.yaml#/components/schemas/LedgerAccountOperationData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,36 @@
get:
tags: [Ledger Accounts]
summary: List ledger account operations
description: |
Returns account-history summary projections for the requested ledger account.
Public HTTP pagination supports only `limit` and `offset`.
Results are ordered by `version` descending and `entry_ref` descending.
Unsupported query parameters, including `archived`, are rejected.
operationId: ledgerAccountOperationsList
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/ledger_account_ref.yaml#/components/parameters/LedgerAccountRef
- $ref: ../parameters/limit.yaml#/components/parameters/Limit
- $ref: ../parameters/offset.yaml#/components/parameters/Offset
responses:
'200':
description: Ledger account operation summaries
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/operation.yaml#/components/schemas/LedgerAccountOperationsData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,15 @@
components:
schemas:
LedgerAccountBalanceData:
description: Response payload containing a ledger account balance.
type: object
additionalProperties: false
required:
- accessToken
- balance
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
balance:
$ref: ../../../models/ledger/balance.yaml#/components/schemas/LedgerAccountBalance
@@ -0,0 +1,33 @@
components:
schemas:
LedgerAccountOperationsData:
description: Response payload containing ledger account history summaries.
type: object
additionalProperties: false
required:
- accessToken
- operations
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
operations:
description: Account-history summaries ordered by `version DESC, entryRef DESC`.
type: array
items:
$ref: ../../../models/ledger/operation.yaml#/components/schemas/LedgerAccountOperationSummary
LedgerAccountOperationData:
description: Response payload containing a single ledger account history projection.
type: object
additionalProperties: false
required:
- accessToken
- operation
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
operation:
description: Account-history projection for the requested entry and ledger account.
$ref: ../../../models/ledger/operation.yaml#/components/schemas/LedgerAccountOperation
@@ -0,0 +1,29 @@
get:
tags: [Organizations]
summary: Get organization by reference
description: Fetches a single organization available to the authenticated account.
operationId: organizationsGet
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/org_ref.yaml#/components/parameters/OrgRef
responses:
'200':
description: Organization details
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/organization.yaml#/components/schemas/OrganizationsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,18 @@
components:
schemas:
OrganizationsAuthData:
description: Authenticated response payload containing organizations.
type: object
additionalProperties: false
required:
- accessToken
- organizations
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
organizations:
description: Collection of organizations available to the authenticated account.
type: array
items:
$ref: ../../../models/organization/organization.yaml#/components/schemas/Organization
@@ -0,0 +1,27 @@
get:
tags: [Organizations]
summary: List organizations of current account
description: Returns organizations the authenticated account can access.
operationId: organizationsList
security:
- bearerAuth: []
responses:
'200':
description: Organizations list
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/organization.yaml#/components/schemas/OrganizationsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,9 @@
components:
parameters:
AccountsRef:
name: accounts_ref
in: path
required: true
description: Account reference, 24 hex chars.
schema:
$ref: ../../models/objectid.yaml#/components/schemas/ObjectId
@@ -0,0 +1,9 @@
components:
parameters:
Archived:
name: archived
in: query
required: false
description: Filter by archive flag. `true` returns archived records, `false` returns active records.
schema:
type: boolean
@@ -0,0 +1,9 @@
components:
parameters:
CallbacksRef:
name: callbacks_ref
in: path
required: true
description: Callback subscription reference, 24 hex chars.
schema:
$ref: ../../models/objectid.yaml#/components/schemas/ObjectId
@@ -0,0 +1,9 @@
components:
parameters:
Cascade:
name: cascade
in: query
required: false
description: If `true`, apply operation to dependent objects where cascade is supported.
schema:
type: boolean
@@ -0,0 +1,9 @@
components:
parameters:
Cursor:
name: cursor
in: query
required: false
description: Opaque cursor from a previous page response (`page.next_cursor`).
schema:
type: string
@@ -0,0 +1,9 @@
components:
parameters:
EntryRef:
name: entry_ref
in: path
required: true
description: Statement entry reference within the requested ledger account history.
schema:
$ref: ../../models/objectid.yaml#/components/schemas/ObjectId
@@ -0,0 +1,11 @@
components:
parameters:
FilterStates:
name: filter_states
in: query
required: false
description: |
Additional payment state filter. Accepts one value or comma-separated values.
Same semantics as `state`/`states`.
schema:
type: string
@@ -0,0 +1,9 @@
components:
parameters:
LedgerAccountRef:
name: ledger_account_ref
in: path
required: true
description: Ledger account reference that scopes the account-history read.
schema:
$ref: ../../models/objectid.yaml#/components/schemas/ObjectId
@@ -0,0 +1,11 @@
components:
parameters:
Limit:
name: limit
in: query
description: Max number of items to return. Parsed as non-negative int64.
required: false
schema:
type: integer
format: int64
minimum: 0
@@ -0,0 +1,11 @@
components:
parameters:
Offset:
name: offset
in: query
description: Number of items to skip. Parsed as non-negative int64.
required: false
schema:
type: integer
format: int64
minimum: 0
@@ -0,0 +1,9 @@
components:
parameters:
OrgRef:
name: org_ref
in: path
required: true
description: Organization reference in BFF route format, 24 hex chars.
schema:
$ref: ../../models/objectid.yaml#/components/schemas/ObjectId
@@ -0,0 +1,9 @@
components:
parameters:
OrganizationsRef:
name: organizations_ref
in: path
required: true
description: Organization reference used by payments/payment-methods/recipients routes.
schema:
$ref: ../../models/objectid.yaml#/components/schemas/ObjectId
@@ -0,0 +1,9 @@
components:
parameters:
Payment MethodsRef:
name: payment_methods_ref
in: path
required: true
description: Payment method reference, 24 hex chars.
schema:
$ref: ../../models/objectid.yaml#/components/schemas/ObjectId
@@ -0,0 +1,10 @@
components:
parameters:
PaymentsRef:
name: payments_ref
in: path
required: true
description: Stable payment reference.
schema:
type: string
minLength: 1
@@ -0,0 +1,9 @@
components:
parameters:
RecipientsRef:
name: recipients_ref
in: path
required: true
description: Recipient reference, 24 hex chars.
schema:
$ref: ../../models/objectid.yaml#/components/schemas/ObjectId
@@ -0,0 +1,11 @@
components:
parameters:
State:
name: state
in: query
required: false
description: |
Payment state filter. Accepts aliases like `accepted`, `settled`, `failed`
or canonical values like `orchestration_state_created`.
schema:
type: string
@@ -0,0 +1,10 @@
components:
parameters:
States:
name: states
in: query
required: false
description: |
Multi-state filter. Provide a comma-separated list with same accepted values as `state`.
schema:
type: string
@@ -0,0 +1,74 @@
get:
tags: [Payment Methods]
summary: List account-owned payment methods
description: |
Returns payment methods owned by `accounts_ref` within `organizations_ref`.
Supports offset pagination and optional archive filtering.
operationId: paymentMethodsListAccountOwned
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/accounts_ref.yaml#/components/parameters/AccountsRef
- $ref: ../parameters/limit.yaml#/components/parameters/Limit
- $ref: ../parameters/offset.yaml#/components/parameters/Offset
- $ref: ../parameters/archived.yaml#/components/parameters/Archived
responses:
'200':
description: Payment methods list
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment_method.yaml#/components/schemas/Payment MethodsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
post:
tags: [Payment Methods]
summary: Create account-owned payment method
description: Creates a payment method owned by `accounts_ref` inside `organizations_ref`.
operationId: paymentMethodsCreateAccountOwned
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/accounts_ref.yaml#/components/parameters/AccountsRef
requestBody:
$ref: ./bodies/payment_method.yaml#/components/requestBodies/PaymentMethodCreateBody
responses:
'201':
description: Payment method created
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment_method.yaml#/components/schemas/Payment MethodsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'409':
$ref: ../response/operation.yaml#/components/responses/Conflict
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,36 @@
post:
tags: [Payment Methods]
summary: Archive/unarchive payment method
description: Sets payment method archive state by `payment_methods_ref` and required `archived` query parameter.
operationId: paymentMethodsArchive
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/payment_methods_ref.yaml#/components/parameters/Payment MethodsRef
- name: archived
in: query
required: true
description: Target archive value to set on the payment method.
schema:
type: boolean
responses:
'200':
description: Archive state updated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment_method.yaml#/components/schemas/Payment MethodsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,17 @@
components:
requestBodies:
PaymentMethodCreateBody:
description: JSON body containing a payment method definition for create.
required: true
content:
application/json:
schema:
$ref: ../request/payment_method.yaml#/components/schemas/PaymentMethodCreateRequest
PaymentMethodUpdateBody:
description: JSON body containing a payment method definition for update.
required: true
content:
application/json:
schema:
$ref: ../request/payment_method.yaml#/components/schemas/PaymentMethodUpdateRequest
@@ -0,0 +1,102 @@
get:
tags: [Payment Methods]
summary: Get payment method
description: Returns payment method by `payment_methods_ref` inside `organizations_ref`.
operationId: paymentMethodsGet
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/payment_methods_ref.yaml#/components/parameters/Payment MethodsRef
responses:
'200':
description: Payment method data
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment_method.yaml#/components/schemas/Payment MethodsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
patch:
tags: [Payment Methods]
summary: Update payment method
description: Updates mutable payment method fields for the record identified by `payment_methods_ref` inside `organizations_ref`.
operationId: paymentMethodsUpdate
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/payment_methods_ref.yaml#/components/parameters/Payment MethodsRef
requestBody:
$ref: ./bodies/payment_method.yaml#/components/requestBodies/PaymentMethodUpdateBody
responses:
'200':
description: Payment method updated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment_method.yaml#/components/schemas/Payment MethodsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'409':
$ref: ../response/operation.yaml#/components/responses/Conflict
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
delete:
tags: [Payment Methods]
summary: Delete payment method
description: Deletes payment method by reference.
operationId: paymentMethodsDelete
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/payment_methods_ref.yaml#/components/parameters/Payment MethodsRef
responses:
'200':
description: Payment method deleted
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment_method.yaml#/components/schemas/Payment MethodsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,74 @@
get:
tags: [Payment Methods]
summary: List recipient-owned payment methods
description: |
Returns payment methods owned by `recipients_ref` within `organizations_ref`.
Supports offset pagination and optional archive filtering.
operationId: paymentMethodsListRecipientOwned
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/recipients_ref.yaml#/components/parameters/RecipientsRef
- $ref: ../parameters/limit.yaml#/components/parameters/Limit
- $ref: ../parameters/offset.yaml#/components/parameters/Offset
- $ref: ../parameters/archived.yaml#/components/parameters/Archived
responses:
'200':
description: Payment methods list
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment_method.yaml#/components/schemas/Payment MethodsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
post:
tags: [Payment Methods]
summary: Create recipient-owned payment method
description: Creates a payment method owned by `recipients_ref` inside `organizations_ref`.
operationId: paymentMethodsCreateRecipientOwned
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/recipients_ref.yaml#/components/parameters/RecipientsRef
requestBody:
$ref: ./bodies/payment_method.yaml#/components/requestBodies/PaymentMethodCreateBody
responses:
'201':
description: Payment method created
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment_method.yaml#/components/schemas/Payment MethodsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'409':
$ref: ../response/operation.yaml#/components/responses/Conflict
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,42 @@
components:
schemas:
PaymentMethodBaseRequest:
type: object
additionalProperties: false
properties:
name:
description: Optional human-readable payment method name.
type: string
description:
description: Optional free-form payment method description.
type: string
nullable: true
type:
description: Payment method type discriminator.
$ref: ../../../external/payment_method_type.yaml#/components/schemas/PaymentMethodType
data:
description: |
Optional payment-method-type-specific payload.
For `type: bankAccount`, this uses the Russian bank-account
destination shape documented as `BankAccountEndpoint`.
type: object
additionalProperties: true
isMain:
description: Optional primary-method flag. When omitted, current handler behavior falls back to `false`.
type: boolean
PaymentMethodCreateRequest:
description: |
Request payload used to create a payment method.
Ownership comes from the route path. The body only carries mutable payment-method fields.
required:
- type
allOf:
- $ref: '#/components/schemas/PaymentMethodBaseRequest'
PaymentMethodUpdateRequest:
description: |
Request payload used to update a payment method.
This is a PATCH contract. Only `name`, `description`, `data`, and `isMain` are mutable.
allOf:
- $ref: '#/components/schemas/PaymentMethodBaseRequest'
@@ -0,0 +1,18 @@
components:
schemas:
Payment MethodsAuthData:
description: Authenticated response payload containing payment methods.
type: object
additionalProperties: false
required:
- accessToken
- payment_methods
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
payment_methods:
description: Collection of payment methods available to the authenticated account.
type: array
items:
$ref: ../../../models/payment_method/payment_method.yaml#/components/schemas/PaymentMethod
@@ -0,0 +1,33 @@
components:
requestBodies:
QuotePaymentBody:
description: JSON payload used to request a quote for one payment intent.
required: true
content:
application/json:
schema:
$ref: ../request/payment.yaml#/components/schemas/QuotePaymentRequest
QuotePaymentsBody:
description: JSON payload used to request quotes for multiple payment intents.
required: true
content:
application/json:
schema:
$ref: ../request/payment.yaml#/components/schemas/QuotePaymentsRequest
InitiatePaymentBody:
description: JSON payload used to initiate a single payment.
required: true
content:
application/json:
schema:
$ref: ../request/payment.yaml#/components/schemas/InitiatePaymentRequest
InitiatePaymentsBody:
description: JSON payload used to initiate multiple payments from a quote reference.
required: true
content:
application/json:
schema:
$ref: ../request/payment.yaml#/components/schemas/InitiatePaymentsRequest
@@ -0,0 +1,37 @@
post:
tags: [Payments]
summary: Initiate payment batch by quote reference
description: |
Executes batch payment from a previously created multi-quote reference. If any quoted item
uses a raw `card` destination, that item's original quote must already include `exp_month`
and `exp_year`. Card-recipient AML screening occurs during execution, not quotation. An
unchanged payment item reuses its persisted compliance decision on idempotent execution
replay, avoiding a duplicate AML call. A definitive denial terminates that payment with
public `failureCode: failure_restriction` and `failureReason: aml_denied`.
operationId: paymentsInitiateBatchByQuote
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
requestBody:
$ref: ./bodies/payment.yaml#/components/requestBodies/InitiatePaymentsBody
responses:
'200':
description: Payment batch initiated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment.yaml#/components/schemas/PaymentsData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,41 @@
post:
tags: [Payments]
summary: Initiate payment using quote reference
description: |
Executes one payment from an existing quote reference. If the quoted destination is raw
`card`, the original quote must already include `exp_month` and `exp_year`. Card-recipient
AML screening occurs during execution, not quotation. An unchanged payment reuses its
persisted compliance decision on idempotent execution replay, avoiding a duplicate AML call.
A definitive denial terminates the payment with public `failureCode: failure_restriction`
and `failureReason: aml_denied`.
operationId: paymentsInitiateByQuote
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
requestBody:
required: true
content:
application/json:
schema:
$ref: ./request/payment.yaml#/components/schemas/InitiatePaymentByQuoteRequest
responses:
'200':
description: Payment initiated by quote
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment.yaml#/components/schemas/PaymentData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,47 @@
get:
tags: [Payments]
summary: Download payment certificate
description: |
Returns a generated payment certificate as binary content.
The payment must be settled; the BFF resolves certificate details from the payment reference.
operationId: paymentsGetPaymentCertificate
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- name: payment_ref
in: query
required: true
description: Settled payment reference used to generate the payment certificate.
schema:
type: string
responses:
'200':
description: Payment certificate file
content:
application/pdf:
schema:
type: string
format: binary
application/octet-stream:
schema:
type: string
format: binary
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'409':
$ref: ../response/operation.yaml#/components/responses/Conflict
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
'503':
description: Upstream service unavailable
content:
application/json:
schema:
$ref: ../response/response.yaml#/components/schemas/ErrorResponse
@@ -0,0 +1,40 @@
get:
tags: [Payments]
summary: List available FX currencies
description: |
Returns the BFF startup-cached Treasury Currency Catalog projection for
client-visible FX currencies. `decimals`, `scale`, and `displayScale` are
presentation fields backed by Treasury `display_scale`.
`accountingScaleCandidate` is informational only and must not be used by
clients to determine executable payout precision, quote precision, or
guaranteed provider support.
The endpoint is authenticated and authorized by `organizations_ref`, but the
returned catalogue is global rather than organization-customized. If Treasury
was unavailable at BFF startup while this endpoint was enabled, BFF fails
startup; if Treasury becomes unavailable after startup, BFF continues serving
the cached catalog revision.
operationId: paymentsFXCurrencies
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
responses:
'200':
description: FX currency catalogue projected from Treasury
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment.yaml#/components/schemas/FXCurrenciesData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'503':
$ref: ../response/operation.yaml#/components/responses/ServiceUnavailable
@@ -0,0 +1,48 @@
get:
tags: [Payments]
summary: List available FX directions
description: |
Returns organization-level FX direction availability.
A returned direction means the organization has at least one eligible
direction-level route. It does not mean that every quote or payment for this
direction will be accepted. The actual route, gateway, limits, pricing, fees,
asset domain, and settlement details are resolved during quotation/payment
execution.
If dependencies are healthy but no organization-eligible executable
directions match oracle quoteable pair sides, the response contains an empty
`directions` array. Oracle or gateway/route registry dependency failures are
returned as errors and are not converted to oracle-only or empty successful
responses.
operationId: paymentsFXDirections
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
responses:
'200':
description: Organization-level directed FX availability
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment.yaml#/components/schemas/FXDirectionsData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'412':
description: Dependency precondition failed
content:
application/json:
schema:
$ref: ../response/response.yaml#/components/schemas/ErrorResponse
'503':
$ref: ../response/operation.yaml#/components/responses/ServiceUnavailable
@@ -0,0 +1,48 @@
post:
tags: [Payments]
summary: Initiate payment from immediate intent
description: |
Creates quote and executes a single payment in one call (request must include `intent`). For
raw `card` destinations, execution requires `exp_month` and `exp_year`; `cardToken`
destinations only require `token`. Card-recipient AML screening occurs during execution.
An unchanged payment reuses its persisted compliance decision on idempotent execution replay,
avoiding a duplicate AML call. A definitive denial terminates the payment with public
`failureCode: failure_restriction` and `failureReason: aml_denied`.
operationId: paymentsInitiateImmediate
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: ./request/payment.yaml#/components/schemas/InitiatePaymentRequest
- type: object
required:
- intent
not:
required:
- quoteRef
responses:
'200':
description: Payment initiated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment.yaml#/components/schemas/PaymentData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,76 @@
get:
tags: [Payments]
summary: List payments in organization
description: |
Returns organization payments with cursor pagination and optional filters.
State filters accept aliases (`accepted`, `settled`, `failed`, etc.) or canonical orchestration states.
operationId: paymentsList
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/cursor.yaml#/components/parameters/Cursor
- $ref: ../parameters/limit.yaml#/components/parameters/Limit
- name: quotation_ref
in: query
required: false
description: Filter by quotation reference used for execution.
schema:
type: string
- name: quote_ref
in: query
required: false
description: Alias of `quotation_ref`.
schema:
type: string
- name: created_from
in: query
required: false
description: Include payments created at or after this RFC3339 timestamp.
schema:
type: string
format: date-time
- name: createdFrom
in: query
required: false
description: Alias of `created_from`.
schema:
type: string
format: date-time
- name: created_to
in: query
required: false
description: Include payments created before this RFC3339 timestamp (must be after `created_from`).
schema:
type: string
format: date-time
- name: createdTo
in: query
required: false
description: Alias of `created_to`.
schema:
type: string
format: date-time
- $ref: ../parameters/state.yaml#/components/parameters/State
- $ref: ../parameters/states.yaml#/components/parameters/States
- $ref: ../parameters/filter_states.yaml#/components/parameters/FilterStates
responses:
'200':
description: Payments list
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment.yaml#/components/schemas/PaymentsData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,37 @@
post:
tags: [Payments]
summary: Quote multiple payment intents
description: |
Calculates a batch quote for multiple payment intents in one request. Each item includes
`executable`, `state`, and optional `blockReason` so callers can skip blocked items. Raw
`card` destinations can omit expiry while quoting, but quoted items intended for later
execution should include `exp_month` and `exp_year`. Card-recipient AML screening is not
performed during quotation; it runs during payment execution, so an executable quote does
not guarantee AML acceptance.
operationId: paymentsMultiQuote
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
requestBody:
$ref: ./bodies/payment.yaml#/components/requestBodies/QuotePaymentsBody
responses:
'200':
description: Quotes generated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment.yaml#/components/schemas/PaymentQuotesData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,31 @@
get:
tags: [Payments]
summary: Get payment by reference
description: Returns a single payment by `payments_ref`.
operationId: paymentsGet
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/payments_ref.yaml#/components/parameters/PaymentsRef
responses:
'200':
description: Payment data
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment.yaml#/components/schemas/PaymentData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,37 @@
post:
tags: [Payments]
summary: Quote single payment intent
description: |
Calculates quote for one payment intent without executing payment. The response includes
`quote.executable`, `quote.state`, and optional `quote.blockReason` so clients can reject
non-executable quotes before attempting execution. Raw `card` destinations can omit expiry
while quoting, but quotes intended for later execution should include `exp_month` and
`exp_year`. Card-recipient AML screening is not performed during quotation; it runs during
payment execution, so an executable quote does not guarantee AML acceptance.
operationId: paymentsQuote
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
requestBody:
$ref: ./bodies/payment.yaml#/components/requestBodies/QuotePaymentBody
responses:
'200':
description: Quote generated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/payment.yaml#/components/schemas/PaymentQuoteData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,30 @@
get:
tags: [Payments]
summary: Get discovery registry snapshot for payments dependencies
description: Returns the latest discovery lookup payload used by payments integrations.
operationId: paymentsRegistryList
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
responses:
'200':
description: Discovery registry payload
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
type: object
additionalProperties: true
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,32 @@
get:
tags: [Payments]
summary: Get latest discovery refresh event for payments dependencies
description: Returns the latest refresh event consumed by the payments API.
operationId: paymentsRegistryRefreshGet
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
responses:
'200':
description: Discovery refresh payload
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
type:
- object
- 'null'
additionalProperties: true
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,163 @@
components:
schemas:
PaymentBase:
description: Base fields shared by payment initiation request payloads.
type: object
additionalProperties: false
required:
- idempotencyKey
properties:
idempotencyKey:
description: Client-supplied key used to safely deduplicate requests.
type: string
metadata:
description: Optional request metadata forwarded through payment processing.
type: object
additionalProperties:
type: string
QuotePaymentRequest:
description: |
Request payload to quote a single payment intent.
For raw `card` destinations, quotation only requires `pan`.
If the quoted payment may later be executed, include `exp_month` and `exp_year` during quotation because execution reuses the quoted endpoint snapshot.
type: object
additionalProperties: false
required:
- intent
properties:
idempotencyKey:
description: Idempotency key used when persisting quote context.
type: string
metadata:
description: Optional metadata associated with the quote request.
type: object
additionalProperties:
type: string
clientPaymentRef:
description: Optional caller-side payment correlation reference to persist with the quote and reuse during execution when the execute request omits it.
type: string
intent:
description: Payment intent to be priced. See `PaymentIntent.destination` for raw-card quote versus execution requirements.
$ref: ../../../models/payment/payment.yaml#/components/schemas/PaymentIntent
previewOnly:
description: If true, returns a preview quote without requiring idempotency.
type: boolean
allOf:
- if:
properties:
previewOnly:
const: true
required:
- previewOnly
then:
not:
required:
- idempotencyKey
else:
required:
- idempotencyKey
QuotePaymentsRequest:
description: |
Request payload to quote multiple payment intents in a single call.
For raw `card` destinations, quotation only requires `pan`.
If quoted items may later be executed, include `exp_month` and `exp_year` during quotation because execution reuses the quoted endpoint snapshot.
type: object
additionalProperties: false
required:
- intents
properties:
idempotencyKey:
description: Idempotency key used when persisting batch quote context.
type: string
metadata:
description: Optional metadata associated with the quote request.
type: object
additionalProperties:
type: string
clientPaymentRef:
description: Optional caller-side batch payment correlation reference to persist with the quote and reuse during execution when the execute request omits it.
type: string
intents:
description: List of payment intents to be priced. See each intent destination for raw-card quote versus execution requirements.
type: array
minItems: 1
items:
$ref: ../../../models/payment/payment.yaml#/components/schemas/PaymentIntent
previewOnly:
description: If true, returns preview quotes without requiring idempotency.
type: boolean
allOf:
- if:
properties:
previewOnly:
const: true
required:
- previewOnly
then:
not:
required:
- idempotencyKey
else:
required:
- idempotencyKey
InitiatePaymentRequest:
description: |
Request payload to initiate a single payment.
When executing a raw `card` destination from inline `intent`, `pan`, `exp_month`, and `exp_year` must be present.
When executing a `cardToken` destination, only `token` is required by current logic.
allOf:
- $ref: ./payment.yaml#/components/schemas/PaymentBase
- type: object
additionalProperties: false
oneOf:
- required: [intent]
- required: [quoteRef]
properties:
intent:
description: Payment intent to execute directly. Raw `card` destinations require expiry at execution time.
$ref: ../../../models/payment/payment.yaml#/components/schemas/PaymentIntent
quoteRef:
description: Reference to a previously generated quote to execute. If that quote contains a raw `card` destination, the original quote must already include `exp_month` and `exp_year`.
type: string
clientPaymentRef:
description: Optional caller-side payment correlation reference. When omitted, execution may reuse the value stored with the quote.
type: string
InitiatePaymentsRequest:
description: |
Request payload to initiate multiple payments from a multi-quote reference.
If any quoted item contains a raw `card` destination, that item's original quote must already include `exp_month` and `exp_year`.
allOf:
- $ref: ./payment.yaml#/components/schemas/PaymentBase
- type: object
additionalProperties: false
required:
- quoteRef
properties:
quoteRef:
description: Reference to a previously generated multi-quote. Raw-card items execute from the stored quoted endpoint snapshot.
type: string
clientPaymentRef:
description: Optional caller-side payment correlation reference. When omitted, execution may reuse the value stored with the quote.
type: string
InitiatePaymentByQuoteRequest:
description: |
Request payload to initiate one payment from an existing quote reference.
If the quote contains a raw `card` destination, the original quote must already include `exp_month` and `exp_year`.
allOf:
- $ref: ./payment.yaml#/components/schemas/PaymentBase
- type: object
additionalProperties: false
required:
- quoteRef
properties:
quoteRef:
description: Reference to a previously generated quote to execute. Execution reuses the stored quoted endpoint snapshot.
type: string
clientPaymentRef:
description: Optional caller-side payment correlation reference. When omitted, execution may reuse the value stored with the quote.
type: string
@@ -0,0 +1,114 @@
components:
schemas:
PaymentQuoteData:
description: Response payload for a single payment quote.
type: object
additionalProperties: false
required:
- accessToken
- quote
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
idempotencyKey:
description: Idempotency key associated with the quote response.
type: string
clientPaymentRef:
description: Caller-supplied payment correlation reference echoed from the quote request, when provided.
type: string
quote:
description: Generated quote data for the requested payment intent.
$ref: ../../../models/payment/payment.yaml#/components/schemas/PaymentQuote
PaymentQuotesData:
description: Response payload for a batch quote request.
type: object
additionalProperties: false
required:
- accessToken
- quote
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
quote:
description: Batch quote summary and quoted items.
type: object
additionalProperties: false
properties:
idempotencyKey:
description: Idempotency key associated with the batch quote response.
type: string
clientPaymentRef:
description: Caller-supplied payment correlation reference echoed from the batch quote request, when provided.
type: string
quoteRef:
description: Reference to the generated batch quote.
type: string
items:
description: Collection of quotes for each requested payment intent.
type: array
items:
$ref: ../../../models/payment/payment.yaml#/components/schemas/PaymentQuote
PaymentsData:
description: Response payload containing a list of payments.
type: object
additionalProperties: false
required:
- accessToken
- payments
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
payments:
description: Collection of payment records.
type: array
items:
$ref: ../../../models/payment/payment.yaml#/components/schemas/Payment
page:
description: Pagination cursor metadata for payment listing endpoints.
$ref: ../../../models/common/pagination.yaml#/components/schemas/CursorPageResponse
PaymentData:
description: Response payload containing a single payment record.
type: object
additionalProperties: false
required:
- accessToken
- payment
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
payment:
description: Requested payment record.
$ref: ../../../models/payment/payment.yaml#/components/schemas/Payment
FXCurrenciesData:
description: Response payload containing the BFF startup-cached Treasury FX currency catalogue projection.
type: object
additionalProperties: false
required:
- currencies
properties:
currencies:
description: Client-visible currencies backed by Treasury Currency Catalog metadata.
type: array
items:
$ref: ../../../models/payment/fx_metadata.yaml#/components/schemas/FXCurrency
FXDirectionsData:
description: Response payload containing organization-level directed FX availability.
type: object
additionalProperties: false
required:
- directions
properties:
directions:
description: Directions with at least one eligible direction-level route for the organization.
type: array
items:
$ref: ../../../models/payment/fx_metadata.yaml#/components/schemas/FXDirection
@@ -0,0 +1,37 @@
get:
tags: [Recipients]
summary: Archive/unarchive recipient
description: Sets recipient archive state by `recipients_ref` and required `archived` query parameter.
operationId: recipientsArchive
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/org_ref.yaml#/components/parameters/OrgRef
- $ref: ../parameters/recipients_ref.yaml#/components/parameters/RecipientsRef
- name: archived
in: query
required: true
description: Target archive value to set on the recipient.
schema:
type: boolean
- $ref: ../parameters/cascade.yaml#/components/parameters/Cascade
responses:
'200':
description: Archive state updated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/recipient.yaml#/components/schemas/RecipientsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,17 @@
components:
requestBodies:
RecipientCreateBody:
description: JSON body containing recipient details for create.
required: true
content:
application/json:
schema:
$ref: ../request/recipient.yaml#/components/schemas/RecipientCreateRequest
RecipientUpdateBody:
description: JSON body containing recipient details for update.
required: true
content:
application/json:
schema:
$ref: ../request/recipient.yaml#/components/schemas/RecipientUpdateRequest
@@ -0,0 +1,33 @@
post:
tags: [Recipients]
summary: Create recipient
description: Creates a recipient inside the organization identified by `org_ref`.
operationId: recipientsCreate
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/org_ref.yaml#/components/parameters/OrgRef
requestBody:
$ref: ./bodies/recipient.yaml#/components/requestBodies/RecipientCreateBody
responses:
'201':
description: Recipient created
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/recipient.yaml#/components/schemas/RecipientsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'409':
$ref: ../response/operation.yaml#/components/responses/Conflict
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,36 @@
get:
tags: [Recipients]
summary: List recipients
description: |
Returns recipients for the specified organization context.
Supports offset pagination and optional archive filtering.
The route currently includes both `org_ref` and `organizations_ref`; the handler resolves organization context from `org_ref` and ignores `organizations_ref`.
operationId: recipientsList
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/org_ref.yaml#/components/parameters/OrgRef
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
- $ref: ../parameters/limit.yaml#/components/parameters/Limit
- $ref: ../parameters/offset.yaml#/components/parameters/Offset
- $ref: ../parameters/archived.yaml#/components/parameters/Archived
responses:
'200':
description: Recipient list
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/recipient.yaml#/components/schemas/RecipientsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,64 @@
get:
tags: [Recipients]
summary: Get recipient by reference
description: Returns a recipient by `recipients_ref`.
operationId: recipientsGet
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/recipients_ref.yaml#/components/parameters/RecipientsRef
responses:
'200':
description: Recipient data
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/recipient.yaml#/components/schemas/RecipientsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
delete:
tags: [Recipients]
summary: Delete recipient
description: Deletes recipient by reference. Use `cascade=true` to remove dependent objects when supported.
operationId: recipientsDelete
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/recipients_ref.yaml#/components/parameters/RecipientsRef
- $ref: ../parameters/cascade.yaml#/components/parameters/Cascade
responses:
'200':
description: Recipient deleted
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/recipient.yaml#/components/schemas/RecipientsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,53 @@
components:
schemas:
RecipientBaseRequest:
type: object
additionalProperties: false
properties:
id:
description: Optional recipient identifier. Required by the current update handler.
$ref: ../../../models/objectid.yaml#/components/schemas/ObjectId
name:
description: Optional human-readable recipient name.
type: string
description:
description: Optional free-form recipient description.
type: string
nullable: true
email:
description: Optional recipient email address.
type: string
format: email
avatarUrl:
description: Optional avatar URL.
type: string
nullable: true
status:
description: Optional recipient status. When omitted, current handler behavior falls back to the model zero value (`ready`).
type: string
enum:
- ready
- registered
- notRegistered
type:
description: Optional recipient type. When omitted, current handler behavior falls back to the model zero value (`internal`).
type: string
enum:
- internal
- external
RecipientCreateRequest:
description: |
Request payload used to create a recipient.
The current create handler does not require any JSON fields beyond a valid object payload; organization context comes from the `org_ref` path parameter.
allOf:
- $ref: '#/components/schemas/RecipientBaseRequest'
RecipientUpdateRequest:
description: |
Request payload used to update a recipient.
The current PUT handler targets the record by `id` and then replaces it with the submitted values; omitted fields may therefore be reset to zero values.
required:
- id
allOf:
- $ref: '#/components/schemas/RecipientBaseRequest'
@@ -0,0 +1,18 @@
components:
schemas:
RecipientsAuthData:
description: Authenticated response payload containing recipients.
type: object
additionalProperties: false
required:
- accessToken
- recipients
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
recipients:
description: Collection of recipients available to the authenticated account.
type: array
items:
$ref: ../../../models/recipient/recipient.yaml#/components/schemas/Recipient
@@ -0,0 +1,31 @@
put:
tags: [Recipients]
summary: Update recipient
description: Updates recipient fields from request payload. The current handler requires `id`; omitted fields may be replaced with zero values.
operationId: recipientsUpdate
security:
- bearerAuth: []
requestBody:
$ref: ./bodies/recipient.yaml#/components/requestBodies/RecipientUpdateBody
responses:
'200':
description: Recipient updated
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/recipient.yaml#/components/schemas/RecipientsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,24 @@
components:
schemas:
ApiError:
description: Standard API error envelope with optional debugging details.
type: object
additionalProperties: false
required:
- code
- error
- source
properties:
code:
description: Application-specific numeric error code.
type: integer
format: int32
error:
description: Human-readable error summary.
type: string
source:
description: Component or subsystem that produced the error.
type: string
details:
description: Optional detailed message providing additional failure context.
type: string
@@ -0,0 +1,85 @@
components:
responses:
Ok:
description: Successful response
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/BaseResponse
Created:
description: Resource created
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/BaseResponse
Accepted:
description: Request accepted for processing
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/BaseResponse
BadRequest:
description: Bad request payload or query/path parameter
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/ErrorResponse
Unauthorized:
description: Unauthorized
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/ErrorResponse
Forbidden:
description: Forbidden
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/ErrorResponse
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/ErrorResponse
Gone:
description: Resource is no longer available
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/ErrorResponse
Conflict:
description: Conflict
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/ErrorResponse
TooManyRequests:
description: Too many requests
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/ErrorResponse
ServiceUnavailable:
description: Service unavailable
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/ErrorResponse
InternalServerError:
description: Internal server error
content:
application/json:
schema:
$ref: ./response.yaml#/components/schemas/ErrorResponse
@@ -0,0 +1,47 @@
components:
schemas:
BaseResponse:
type: object
additionalProperties: false
required:
- status
- data
properties:
status:
$ref: ./status.yaml#/components/schemas/ApiStatus
data:
description: Payload for success or error responses.
ErrorResponse:
allOf:
- $ref: ./response.yaml#/components/schemas/BaseResponse
- type: object
properties:
status:
type: string
enum:
- error
data:
$ref: ./error.yaml#/components/schemas/ApiError
SuccessResultData:
type: object
additionalProperties: false
required:
- result
properties:
result:
type: boolean
SuccessResultResponse:
allOf:
- $ref: ./response.yaml#/components/schemas/BaseResponse
- type: object
properties:
status:
type: string
enum:
- success
- processed
data:
$ref: ./response.yaml#/components/schemas/SuccessResultData
@@ -0,0 +1,10 @@
components:
schemas:
ApiStatus:
type: string
description: Unified response status used by backend wrappers.
enum:
- success
- processed
- error
- request
@@ -0,0 +1,17 @@
components:
requestBodies:
VerificationCodeBody:
description: JSON payload used to request a new verification code.
required: true
content:
application/json:
schema:
$ref: ../request/verification.yaml#/components/schemas/VerificationCodeRequest
VerifyCodeBody:
description: JSON payload containing a verification code to validate.
required: true
content:
application/json:
schema:
$ref: ../request/verification.yaml#/components/schemas/CodeVerificationRequest
@@ -0,0 +1,37 @@
post:
tags: [Verification, Auth]
summary: Request verification code
description: |
Creates a verification challenge for the specified purpose/target.
For `purpose=login`, request must be authorized with a pending account token.
operationId: verificationRequestCode
security:
- bearerAuth: []
requestBody:
$ref: ./bodies/verification.yaml#/components/requestBodies/VerificationCodeBody
responses:
'202':
description: Verification code requested
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/verification.yaml#/components/schemas/VerificationResponseData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'409':
$ref: ../response/operation.yaml#/components/responses/Conflict
'429':
$ref: ../response/operation.yaml#/components/responses/TooManyRequests
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,73 @@
components:
schemas:
VerificationCodeRequest:
type: object
additionalProperties: false
required:
- purpose
properties:
purpose:
type: string
description: Verification purpose, e.g. login.
target:
type: string
format: email
description: Optional destination override. When omitted, current handler falls back to the authenticated account email/login.
idempotencyKey:
type: string
quoteRef:
description: Required when `purpose` is `payout`; omitted for login and other verification purposes.
type: string
allOf:
- if:
properties:
purpose:
const: payout
required:
- purpose
then:
required:
- quoteRef
CodeVerificationRequest:
type: object
additionalProperties: false
required:
- purpose
- code
properties:
purpose:
type: string
description: Verification purpose, e.g. login.
target:
type: string
format: email
description: Optional destination override. When omitted, current handler falls back to the authenticated account email/login.
idempotencyKey:
type: string
quoteRef:
description: Required when `purpose` is `payout`; omitted for login and other verification purposes.
type: string
code:
type: string
sessionIdentifier:
$ref: ../../../models/auth/session_identifier.yaml#/components/schemas/SessionIdentifier
allOf:
- if:
properties:
purpose:
const: login
required:
- purpose
then:
required:
- sessionIdentifier
- if:
properties:
purpose:
const: payout
required:
- purpose
then:
required:
- quoteRef
@@ -0,0 +1,37 @@
post:
tags: [Verification, Auth]
summary: Resend verification code
description: |
Re-issues a verification challenge using the same request shape as `/verification`.
Cooldown and retry limits are enforced by backend verification storage policy.
operationId: verificationResendCode
security:
- bearerAuth: []
requestBody:
$ref: ./bodies/verification.yaml#/components/requestBodies/VerificationCodeBody
responses:
'202':
description: Verification code resent
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/verification.yaml#/components/schemas/VerificationResponseData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'409':
$ref: ../response/operation.yaml#/components/responses/Conflict
'429':
$ref: ../response/operation.yaml#/components/responses/TooManyRequests
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,35 @@
components:
schemas:
VerificationResponseData:
description: Response data returned after requesting a verification code.
type: object
additionalProperties: false
required:
- idempotencyKey
- ttl_seconds
- cooldown_seconds
- target
properties:
idempotencyKey:
description: Idempotency key associated with the verification request.
type: string
ttl_seconds:
description: Verification code validity period in seconds.
type: integer
format: int32
cooldown_seconds:
description: Cooldown period before another code can be requested.
type: integer
format: int32
target:
description: Destination where the verification code was sent.
type: string
quoteRef:
description: Payment quote reference echoed for payout verification requests.
type: string
VerifyResultData:
description: Result payload returned after code verification succeeds.
oneOf:
- $ref: ../../accounts/response/auth.yaml#/components/schemas/LoginData
- $ref: ../../response/response.yaml#/components/schemas/SuccessResultData
@@ -0,0 +1,37 @@
post:
tags: [Verification, Auth]
summary: Verify code and complete pending flow
description: |
Verifies submitted code and consumes verification token.
For login purpose, returns full auth payload (access + refresh tokens); for other purposes returns operation result.
operationId: verificationVerifyCode
security:
- bearerAuth: []
requestBody:
$ref: ./bodies/verification.yaml#/components/requestBodies/VerifyCodeBody
responses:
'200':
description: Verification successful
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/verification.yaml#/components/schemas/VerifyResultData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'404':
$ref: ../response/operation.yaml#/components/responses/NotFound
'410':
$ref: ../response/operation.yaml#/components/responses/Gone
'409':
$ref: ../response/operation.yaml#/components/responses/Conflict
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,35 @@
get:
tags: [Wallets]
summary: List live managed-wallet assets
description: |
Returns the live wallet asset catalogue currently announced by healthy CRYPTO
gateways in discovery. The endpoint is authenticated and authorized by
`organizations_ref`, but the returned asset list is gateway-driven rather than
organization-customized. Malformed gateway asset announcements are skipped.
If discovery is available but no valid wallet assets are currently announced,
the response contains an empty `assets` array.
operationId: walletAssetsList
security:
- bearerAuth: []
parameters:
- $ref: ../parameters/organizations_ref.yaml#/components/parameters/OrganizationsRef
responses:
'200':
description: Live managed-wallet asset catalogue
content:
application/json:
schema:
allOf:
- $ref: ../response/response.yaml#/components/schemas/BaseResponse
- type: object
properties:
data:
$ref: ./response/wallet.yaml#/components/schemas/WalletAssetsAuthData
'400':
$ref: ../response/operation.yaml#/components/responses/BadRequest
'401':
$ref: ../response/operation.yaml#/components/responses/Unauthorized
'403':
$ref: ../response/operation.yaml#/components/responses/Forbidden
'500':
$ref: ../response/operation.yaml#/components/responses/InternalServerError
@@ -0,0 +1,18 @@
components:
schemas:
WalletAssetsAuthData:
description: Authenticated response payload containing live wallet assets.
type: object
additionalProperties: false
required:
- accessToken
- assets
properties:
accessToken:
description: Refreshed access token to be used in subsequent API calls.
$ref: ../../../models/auth/token_data.yaml#/components/schemas/TokenData
assets:
description: Managed-wallet assets currently announced by healthy CRYPTO gateways.
type: array
items:
$ref: ../../../models/wallet/wallet_asset.yaml#/components/schemas/WalletAsset
+10
View File
@@ -0,0 +1,10 @@
components:
schemas:
ChainNetwork:
type: string
enum:
- unspecified
- ethereum_mainnet
- arbitrum_one
- tron_mainnet
- tron_nile
+15
View File
@@ -0,0 +1,15 @@
components:
schemas:
EndpointType:
type: string
enum:
- paymentMethod
- account
- recipient
- ledger
- managedWallet
- cryptoAddress
- card
- cardToken
- bankAccount
- iban
+7
View File
@@ -0,0 +1,7 @@
components:
schemas:
FxSide:
type: string
enum:
- buy_base_sell_quote
- sell_base_buy_quote
+8
View File
@@ -0,0 +1,8 @@
components:
schemas:
PaymentKind:
type: string
enum:
- payout
- internal_transfer
- fx_conversion
@@ -0,0 +1,12 @@
components:
schemas:
PaymentMethodType:
type: string
enum:
- iban
- card
- cardToken
- bankAccount
- wallet
- cryptoAddress
- ledger
Loaded 100 of 556 files, more files were not shown because too many files have changed in this diff. Show more