Description
Overview
The products package provides functionality for managing banking products, their configurations, and settings. It supports various product types including funds transfers, card transactions, loan deposits, and account types with flexible settings management.
API Methods
Get All Products
GET /v1/products
Retrieves a list of all products with advanced querying, filtering, sorting, and pagination capabilities.
Each data[] entry is a ProductCatalogRead: name and description are resolved for the request’s Accept-Language (same negotiation as pre-flight). Locale maps are not returned on this endpoint.
Query Parameters
active- Filter by active status (boolean)type- Filter by product type (string)code- Filter by product code (string)page- Page number for pagination (default: 1)per_page- Items per page (default: 20)
Response
{
"data": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"code": "IWT",
"type": "transfers",
"name": "Internal Wire Transfer",
"description": "Transfer funds between internal accounts",
"settings": {
"min_amount": 100,
"max_amount": 100000000,
"daily_limit": 10000000,
"fee_structure": {
"type": "fixed",
"fixed_amount": 0
},
"processing_time": "instant",
"requires_approval": false
},
"active": true,
"created_at": "2024-03-20T10:00:00Z",
"created_by": "123e4567-e89b-12d3-a456-426614174001",
"modified_at": "2024-03-20T10:00:00Z",
"modified_by": "123e4567-e89b-12d3-a456-426614174001",
"metadata": {}
}
],
"total": 15,
"total_unfiltered": 20,
"limit": 20,
"offset": 0,
"page": 1,
"pages": 1
}Advanced Query Parameters
sort- Sort field (e.g., "name", "created_at")order- Sort order ("asc" or "desc")search- Legacy top-level text searchsearch._text.like- Localized text search across resolved product name and description, includingname_i18n/description_i18nvalues (example:search._text.like=Crypto w)created_after- Filter by creation datecreated_before- Filter by creation date
Get Product by ID
GET /v1/products/{id}
Retrieves detailed information about a specific product by its UUID.
Response
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"code": "IWT",
"type": "transfers",
"name": "Internal Wire Transfer",
"description": "Transfer funds between internal accounts",
"settings": {
"min_amount": 100,
"max_amount": 100000000,
"daily_limit": 10000000,
"fee_structure": {
"type": "fixed",
"fixed_amount": 0
},
"processing_time": "instant",
"requires_approval": false,
"supported_currencies": ["EUR", "USD", "CHF"],
"compliance_rules": ["kyc_verification"]
},
"active": true,
"created_at": "2024-03-20T10:00:00Z",
"created_by": "123e4567-e89b-12d3-a456-426614174001",
"modified_at": "2024-03-20T10:00:00Z",
"modified_by": "123e4567-e89b-12d3-a456-426614174001",
"metadata": {}
}Get Product by Code
GET /v1/products/code/{code}
Retrieves a product by its code (e.g., "IWT", "OWT").
Get Products by Type
GET /v1/products/type/{type}
Retrieves all products of a specific type.
Supported Types
transfers- Wire transfers and payment routing (IWT, OWT, INT, OWN, OFR, …)fx- Foreign exchange and currency conversioncredits- Credit facilities and lending productsdeposits- Deposit and savings productscards- Card issuance and card transaction products
Create Product
POST /v1/products
Creates a new banking product with specified configuration.
Request Body
{
"code": "NEW",
"type": "transfers",
"name": "New Transfer Product",
"description": "Custom transfer product",
"settings": {
"min_amount": 500,
"max_amount": 50000000,
"daily_limit": 5000000,
"fee_structure": {
"type": "percentage",
"percentage": 0.001
},
"processing_time": "1-2 business days",
"requires_approval": true,
"supported_currencies": ["EUR", "USD"],
"compliance_rules": ["kyc_verification", "aml_check"]
},
"active": true
}Update Product
PUT /v1/products/{id}
Updates an existing product's configuration and settings.
Request Body
{
"name": "Updated Product Name",
"description": "Updated description",
"settings": {
"min_amount": 1000,
"max_amount": 100000000,
"fee_structure": {
"type": "tiered",
"tiers": [
{
"min_amount": 0,
"max_amount": 1000000,
"fixed_amount": 100
},
{
"min_amount": 1000000,
"percentage": 0.0005
}
]
}
},
"active": true
}Delete Product
DELETE /v1/products/{id}
Deletes a product from the system.
Product Settings Structure
Products support flexible configuration through the settings field, which can include:
Transfer Settings
min_amount- Minimum transfer amount in centsmax_amount- Maximum transfer amount in centsdaily_limit- Daily transfer limit in centsmonthly_limit- Monthly transfer limit in centsprocessing_time- Processing time descriptioncutoff_time- Daily cutoff time for processingsupported_currencies- Array of supported currency codesrequires_approval- Whether manual approval is requiredauto_approve- Whether auto-approval is enabledrisk_level- Risk level (low, medium, high)compliance_rules- Array of compliance rules to apply
Fee Structure
type- Fee type: "fixed", "percentage", or "tiered"fixed_amount- Fixed fee in centspercentage- Percentage fee (0.01 = 1%)tiers- Array of fee tiers for tiered pricingmin_fee- Minimum fee in centsmax_fee- Maximum fee in cents
Quote Settings
quote.fx_source- Authoritative internal FX source for transfer-owned locked quote pricing. This is a server-owned product policy value (for exampleCRP,CMC,ECB, orCC), not a client-controlled request field.
Localised Names and Descriptions (§17)
Product name and description are locale-resolved at read time. The source of truth is stored in two JSONB columns:
name_i18n— locale → display name mapping (e.g.{"en": "Outbound Wire Transfer", "de": "Ausgehende Überweisung"})description_i18n— locale → description mapping
Locale selection — send an Accept-Language header (BCP 47, e.g. de, fr-CH). The server picks the best match from supported locales and falls back to the tenant's configured default locale when no match is found.
Catalog read JSON (GET /v1/products list data[], GET /v1/products/{id}, GET /v1/products/code/{code}, GET /v1/products/type/{type}, and the POST / PUT response bodies) uses the ProductCatalogRead shape: name and description are always resolved strings from Accept-Language plus the tenant default — name_i18n / description_i18n are not serialized on those responses. Exception: GET /v1/products/{id} and GET /v1/products/code/{code} accept optional query include_i18n=true (1 / yes); when present and the caller has update permission on that product, the JSON body is a ProductCatalogEditorRead: same resolved fields plus name_i18n and description_i18n maps for admin tools (403 if the flag is set but update is denied). Pre-flight APIs use the same resolution rules on ProductSummary inside PreFlightResponse and ProductListResponse; those objects also expose only resolved strings, not locale maps.
Product matrix (pre-flight & list)
These customer-scoped endpoints evaluate active product matrix rules. They require a valid JWT and RBAC read on the target customer_id. The machine-readable contract lives in preflight.openapi.json alongside this file.
Client journey: discovery → transfer execution
-
Discovery — While the user narrows products, source account, destination (own account or counterparty), channel, currency, and amount, the client calls
POST /v1/products/pre-flight(and optionallyPOST /v1/products/list) with partialPreFlightRequestfilters. The response includestransfer_paramswhen product, source, and destination are all pinned so the UI can show allowed/deny, limits, and fee hints before the user commits. -
Execution — Pre-flight does not call the transfers API. When the user confirms, the client submits payment through
POST /v1/transfers/finalize(OpenAPI:OpenAPI schema, schemaCreatePaymentRequest). Customertransactionsv2 “complete” flows that create real money movement delegate to the same finalize path internally.
The finalize JSON uses different wire names than the pre-flight filter (for example sender_id instead of source_account_id, nested recipient instead of flat destination_*, and amount.amount_minor instead of amount.amount on the wire — both represent minor-unit strings plus currency; precision is optional metadata). The server builds the same internal matrix input the pre-flight engine uses (transfers.PreFlightRequestFromCreatePayment), normalizes finalize product selection into pre-flight product_ids[] (resolving finalize product_code to a product UUID before matrix evaluation when needed), resolves the exact destination to the universal pre-flight selector destination_account_id = counterparties.cp_accounts.id when possible, runs products.ValidatePreFlightRequest, then products.PreFlightForFinalize before persisting the transfer. A matrix deny returns 422 with message code transfers_m.preflight_denied. Treat pre-flight responses as advisory for UX; the finalize request is authoritative subject to hydration, RBAC, idempotency, and quote rules.
Pre-flight filter (PreFlightRequest) | Finalize body (CreatePaymentRequest) |
|---|---|
customer_id | customer_id |
product_ids[] | product_code / product_id (server normalizes finalize product selection into pre-flight product_ids[] before matrix evaluation) |
source_account_id | sender_id |
destination_account_id | Exact universal destination selector (counterparties.cp_accounts.id) resolved server-side from recipient.type = account, recipient.account_id, or from the selected counterparty instrument |
destination_counterparty_id | Coarse counterparty filter built from recipient.type = recipient, recipient.id before exact destination normalization |
channel | channel |
amount (amount, currency, optional precision) | amount (amount_minor, currency, optional precision) — same minor-units semantics |
Pre-flight
POST /v1/products/pre-flight
Returns eligible products, counterparty-shaped sources, counterparty-shaped destinations, routes (viable channels per source-account / exact destination cp_account_id), optional transfer_params when product, source, destination, channel, and amount are pinned, and foreign_counterparties_allowed. The target customer itself is represented as its own/private counterparty row, matching the counterparties domain model. sources[] and destinations[] intentionally reuse counterparties response collection names: own_accounts[], bank_accounts[], and crypto_wallets[]. Selectable nested rows carry cp_account_type (account | bank_account | crypto_wallet), cp_account_id for follow-up pre-flight destination_account_id / route matching, products_allowed, and finalize_recipient hints that match transfers/finalize CreatePaymentRequest.recipient. transfer_params.amount echoes the normalized evaluated amount in minor units with precision metadata. Each products[] entry is a ProductSummary including route (payment | convert | deposit) for client navigation.
Product list
POST /v1/products/list
Returns products allowed for the customer scope. Embedded ProductSummary rows follow the same Accept-Language resolution rules as pre-flight and include route (payment | convert) so the client can pick the correct SPA screen.
Write (create / update)
Pass name_i18n and description_i18n objects in the request body to set locale-specific strings:
{
"code": "OWT",
"type": "transfers",
"name_i18n": {
"en": "Outbound Wire Transfer",
"de": "Ausgehende Überweisung",
"fr": "Virement sortant"
},
"description_i18n": {
"en": "Send funds to external bank accounts via wire transfer.",
"de": "Überweisen Sie Gelder an externe Bankkonten.",
"fr": "Envoyez des fonds vers des comptes bancaires externes."
}
}The legacy top-level name / description strings are still accepted on write and are stored on their existing columns. They act as the read-time fallback when name_i18n / description_i18n is absent or has no entry for the resolved locale (no automatic copy into the JSONB map is performed at write time).
Custom Fields
custom_fields- Additional custom configuration as key-value pairs
Error Handling
The API returns appropriate HTTP status codes and error messages:
400 Bad Request- Invalid input data or malformed request401 Unauthorized- Missing or invalid authentication403 Forbidden- Insufficient permissions404 Not Found- Product not found409 Conflict- Product code already exists500 Internal Server Error- Server error
Error responses include detailed error messages in multiple languages (EN, DE, FR, IT).