# Payments The Payments API lets you submit outgoing credit transfers, track their status, and — for banks/customers configured with pre-approved payments — route them through a signing basket before they reach the bank. ## Concepts - A payment request creates one **bulk payment (P1B)**, which contains one or more **payment lines (P1P)**. A single request can submit several payment lines at once. - **Always resolve the real outcome at the P1P (line) level, not just P1B.** A bulk payment can show a partial status (`PART`) while its individual lines have different outcomes from each other. - Whether a payment requires manual sign-off depends on the account's approval model: - **Non pre-approved (RGB off):** the payment is sent straight to the bank with no signing step, and then the customer needs to do a manual approval withing the online bank. - **Pre-approved (RGB on):** the payment stays at `RCVD` until it's approved through the [signing basket flow](#signing-baskets). - Which model applies depends on the bank and how the customer's integration was ordered — RGB configuration is not identical across banks (see [Troubleshooting](#troubleshooting--known-gotchas)). - **RGB ON is the recommended setup for the best user flow**, and the signing basket is the recommended way to approve payments within that setup. ## Common headers | Header | Value | | --- | --- | | `Authorization` | `Bearer {access_token}` | | `Channel-Type` | `openBanking` | | `Subscription-Id` | `{subscriptionId}` | | `Resource-Group-Name` | `{resourceGroupId}` | | `TPP-Redirect-URI` | Your configured bank signing/redirect URL | | `Accept` | `application/json` | | `Content-Type` | `application/json` (when the request has a body) | | `api-version` | `1.0` | | `Idempotency-Key` | `{UUID}` — recommended on every POST, to safely retry without creating duplicate payments | ## Submit bulk payment | Method | Endpoint | Body | | --- | --- | --- | | `POST` | `{BankingBaseUrl}/api/bulk-payments/credit-transfer` | JSON, structure below | ```json { "debtorAccount": { "iban": "...", "bban": "...", "currency": "..." }, "debtorName": "...", "debtorAddress": { "streetName": "...", "postCode": "...", "townName": "...", "country": "..." }, "batchBooking": false, "requestedExecutionDate": "...", "paymentLines": [ { "endToEndIdentification": "...", "instructedAmount": { "currency": "...", "amount": "..." }, "creditorAccount": { "iban": "...", "bban": "..." }, "creditorName": "...", "creditorAddress": { "streetName": "...", "postCode": "...", "townName": "...", "country": "..." }, "remittanceInformationUnstructured": "...", "remittanceInformationStructured": { "reference": "...", "referenceType": "SCOR|CINV" }, "purposeCode": "...", "purposeProprietary": "...", "regulatoryReportingCode": "...", "regulatoryReportingInformation": "...", "bundleReference": "..." } ] } ``` Fields with empty values are normally omitted from the request. `paymentLines` can contain multiple payment lines in a single call. Include as much remittance/reference information as you have — for cross-border payments, IBAN, SWIFT/BIC, and country codes are required. The payment goes through initial validation (illegal characters, etc.) before being sent onward, so malformed requests fail fast rather than reaching the bank. ### Structured reference (`remittanceInformationStructured`) `referenceType` identifies which *kind* of structured reference is used — you don't need to (and shouldn't) pick the local reference format explicitly. The local form is set implicitly based on the account/country data in the API call itself. Examples of local equivalents behind the same `referenceType`: | Country | Local reference name | `referenceType` | | --- | --- | --- | | Norway | KID | `SCOR` | | Sweden | OCR | `SCOR` | | Denmark | FIK | `SCOR` (mapped to FIK locally) | | General ISO/creditor reference | — | `SCOR` | | Invoice-based reference | — | `CINV` | In other words: KID in Norway and OCR in Sweden are the *same underlying concept* (a structured payment reference), just under different local names — the API represents them with the same `referenceType` value, and the correct local variant is applied automatically based on the payment's country/account context. ## Domestic versus non-domestic payments There is no separate `domestic` / `international` flag. Domestic and non-domestic payments are sent to the **same endpoint** using the **same JSON structure** — the API distinguishes them based on the account, currency, country, and payment-agent data you provide. In simplified terms: - **Domestic:** debtor and creditor are normally in the same country, the same local currency is used, and BBAN or IBAN can be sent without a foreign payment agent. - **Non-domestic:** the creditor is in another country, or the payment uses another currency. In this case, send the creditor's IBAN and — where available — `creditorAgent` (SWIFT/BIC) and `creditorAgentCountryCode`. ### Example: domestic payment A Swedish payment in SEK to a Swedish account. `creditorAgent` can be omitted if no SWIFT code is registered for the recipient's bank. ```json { "debtorAccount": { "iban": "SE3550000000054910000003", "bban": "54910000003", "currency": "SEK" }, "debtorName": "Aritma AB", "debtorAddress": { "streetName": "Example Street 1", "postCode": "111 22", "townName": "Stockholm", "country": "SE" }, "batchBooking": false, "requestedExecutionDate": "2026-09-25", "paymentLines": [ { "endToEndIdentification": "V00001234", "instructedAmount": { "currency": "SEK", "amount": "12500.00" }, "creditorAccount": { "iban": "SE4550000000054910000019", "bban": "54910000019" }, "creditorName": "Supplier Sweden AB", "creditorAddress": { "streetName": "Supplier Road 2", "postCode": "411 10", "townName": "Gothenburg", "country": "SE" }, "remittanceInformationUnstructured": "Invoice 1234", "remittanceInformationStructured": { "reference": "1234567890", "referenceType": "SCOR" }, "creditorAgentCountryCode": "SE", "bundleReference": "{guid}" } ] } ``` ### Example: non-domestic payment A payment from Sweden to a Norwegian account in NOK. The recipient's IBAN and SWIFT/BIC are used. `creditorAgent` is only populated when the recipient bank account has a SWIFT value on record. ```json { "debtorAccount": { "iban": "SE3550000000054910000003", "bban": "54910000003", "currency": "SEK" }, "debtorName": "Aritma AB", "debtorAddress": { "streetName": "Example Street 1", "postCode": "111 22", "townName": "Stockholm", "country": "SE" }, "batchBooking": false, "requestedExecutionDate": "2026-09-25", "paymentLines": [ { "endToEndIdentification": "V00001235", "instructedAmount": { "currency": "NOK", "amount": "12500.00" }, "creditorAccount": { "iban": "NO9386011117947" }, "creditorName": "Supplier Norway AS", "creditorAddress": { "streetName": "Supplier Road 2", "postCode": "0150", "townName": "Oslo", "country": "NO" }, "creditorAgent": "DNBANOKK", "creditorAgentCountryCode": "NO", "remittanceInformationUnstructured": "Invoice 1234", "bundleReference": "{guid}" } ] } ``` ### How the classification actually works There's no explicit `domestic = true/false` field — the distinction is implicit in the fields you send, combined with the API's own rules: | Field | Where it comes from | | --- | --- | | `debtorAccount.currency` | The debtor's bank account | | `instructedAmount.currency` | The payment currency | | `creditorAccount` | Populated with IBAN and/or BBAN, depending on which values are available | | `creditorAddress.country` | The creditor's country code | | `creditorAgent` | Set to SWIFT/BIC when a value is available for the creditor's bank | | `creditorAgentCountryCode` | Always set from the creditor's country code | ## Retrieve and cancel a payment | Method | Endpoint | Body | | --- | --- | --- | | `GET` | `{BankingBaseUrl}/api/bulk-payments/credit-transfer/{paymentId}` | No body | | `DELETE` | `{BankingBaseUrl}/api/bulk-payments/credit-transfer/{paymentId}` | No body | The same endpoint pattern is used to check status for both the complete bulk transfer (P1B) and individual payment lines (P1P) — as noted above, resolve the real per-line outcome rather than relying on the P1B-level status alone. ### Status progression Full ISO 20022 status flow: `RCVD` → `ACTC` (Accepted Technical Validation) → `ACCP` (Accepted Customer Profile) → `ACSP` (Accepted Settlement In Process) → `ACSC` (Accepted Settlement Completed) with `RJCT` (rejected) or `PART` (partially accepted) as alternative branches. On rejection, check the status message / reason code returned with the payment. Prefer **webhooks** over polling to track status changes (see below). ## Signing baskets Used when an account has **pre-approved payments (RGB) enabled** — the payment stays at `RCVD` until the basket is created and authorized. | Method | Endpoint | Body | | --- | --- | --- | | `POST` | `{BankingBaseUrl}/api/signing-baskets` | `{ "paymentIds": ["{paymentId1}", "{paymentId2}"] }` | | `POST` | `{BankingBaseUrl}/api/signing-baskets/{basketId}/authorizations` | Empty body; the signing redirect is returned via the `TPP-Redirect-URI` header | Multiple payment IDs can be included in one basket to approve several payments at once. After authorization, the response includes a redirect URL where the authorized user completes BankID verification and approves the basket; they're then redirected back to the configured `TPP-Redirect-URI`. Both P1B (bulk payment) and P1P (individual payment line) IDs can be added to a signing basket. **We recommend adding P1P IDs** rather than P1B IDs, since this gives a clean 1:1 relationship between what's approved and what's actually sent — a P1B can contain multiple lines with different outcomes, which makes basket-level approval harder to reason about. A payment is only sent on to the bank once it has been fully approved — 1 out of 1, or 2 out of 2, signatures, depending on how the account's approval requirement (`numberOfApprovers`) is configured. Only after that full approval is reached does the payment actually leave Aritma for the bank. ## Tracking status via webhooks Rather than polling, subscribe to payment-related events on the [Events API](https://developer.aritma.com/apis/platform/events): | Function | Event(s) | Callback path | | --- | --- | --- | | Payment/transfer status | `banking.payment.status.updated`, `banking.bulk_payment.status.updated` | `/api/status_update/{tenantId}/{companyId}` | After subscribing, the subscription must be validated via the callback included in the subscription flow. ## Troubleshooting / known gotchas | Symptom | Cause | What to do | | --- | --- | --- | | Payment stuck at `RCVD` | Account has pre-approved payments (RGB) enabled | Complete the [signing basket flow](#signing-baskets) | | Bulk payment status looks wrong or incomplete | You're reading only the P1B-level status | Always resolve the real outcome at the P1P (payment line) level | | Unsure whether an account needs signing | RGB configuration differs by bank/country — e.g. most Norwegian banks use an Aritma toggle, while DNB and banks in Sweden/Denmark require RGB to be ordered as part of the bank agreement, and Handelsbanken doesn't support it until Q4 2026 | Check with the customer's bank onboarding setup, or contact Aritma support if unsure | For anything not covered above — production incidents, account-specific payment failures, or billing — escalate to **support@aritma.com**