Version: 1.0 · Berlin Group NextGenPSD2 · 2026-05-15
This document describes the DTC Open API endpoints for DTC acting as a Third Party Provider (TPP) under the EU PSD2 directive. The surface implements two of the three TPP sub-roles defined by Berlin Group NextGenPSD2:
The shared Consent lifecycle endpoints and the unauthenticated SCA Callback endpoint are documented alongside.
| Term | Full Name | Meaning in this API |
|---|---|---|
| PSU | Payment Service User | The end-user; an account holder at an EU bank (the ASPSP) who authorises DTC to access their accounts or initiate payments on their behalf. |
| TPP | Third Party Provider | The licensed intermediary. In this surface DTC plays the TPP role. |
| ASPSP | Account Servicing PSP | The PSU's holding bank / EMI (any EU PSD2-licensed ASPSP). DTC speaks to the ASPSP over Berlin Group APIs on behalf of the PSU. |
| AISP | Account Information SP | TPP sub-role for reading accounts / balances / transactions. |
| PISP | Payment Initiation SP | TPP sub-role for initiating payments from the PSU's account at the ASPSP. |
| SCA | Strong Customer Authentication | Two-factor authentication performed by PSU on the ASPSP side (password + OTP / biometric). |
| Consent | — | The credential issued by the ASPSP (after PSU SCA) that lets the TPP exercise a scope (AIS / PIS) for a finite window. |
+-----+ HTTPS +---------------+ HTTPS +-----------+ PSD2 +-------+
| PSU | <-----> | DTC Wallet | <-----> | DTC TPP | <----> | ASPSP |
| | | (Client App) | | (this) | | (Bank)|
+-----+ +---------------+ +-----------+ +-------+
^ | ^
| SCA redirect / poll | |
+--------------------------------------------+------------------+
(PSU is redirected to the ASPSP for SCA, then back to DTC)
Every business call goes through DTC: the wallet client authenticates to DTC with OAuth 2.0 + HMAC-SHA512 signature; DTC translates that into a Berlin Group request to the ASPSP. The SCA itself is delegated to the ASPSP — the PSU never enters bank credentials in the DTC UI.
The PSD2 TPP Open API provides four layers of security:
API Key Management page.access_token in every business call.API Key Management page.+ Create to open the dialog.API Key, API Secret, and Sign Key will be generated and shown one time only. Save them safely before closing the dialog.PSD2_AIS, PSD2_PIS.To use OAuth 2.0, first call Fetch Access Token. Then add the header
Authorization: Bearer {access_token} to every PSD2 Open API request.
If the access token expires you can re-fetch it or use the Fetch Access Token by Refresh Token API. We recommend fetching a new access token before the previous one expires.
Exchange your API Key + API Secret for an access token using the OAuth 2.0
Client Credentials grant.
curl -X "POST" "https://{host}/openapi/auth/oauth2/token" \
-H 'Content-Type: multipart/form-data; charset=utf-8; boundary=__X_PAW_BOUNDARY__' \
-F "client_id=xxx" \
-F "client_secret=xxx" \
-F "grant_type=client_credentials"
| Field | Type | Required | Description |
|---|---|---|---|
client_id | String | R | The API Key value generated in step 2.2. |
client_secret | String | R | The API Secret value generated in step 2.2. |
grant_type | String | R | Fixed value client_credentials. |
{
"access_token": "CkppLkyiqEUKITGdtCZRUZBl",
"expires_in": 21600,
"refresh_token": "CpCAhcCRtLU4kPjs54omWW3A",
"rt_expires_in": 43200,
"token_type": "bearer"
}
| Field | Type | Description |
|---|---|---|
access_token | String | Bearer token to put into the Authorization header of subsequent calls. Keep it secret. |
expires_in | Integer | Access-token validity in seconds. |
refresh_token | String | Refresh token used to obtain a new access token before the current one expires. |
rt_expires_in | Integer | Refresh-token validity in seconds. |
token_type | String | Fixed value bearer. |
Exchange a valid refresh_token for a new access token (and a fresh refresh token).
curl -X "POST" "https://{host}/openapi/auth/oauth2/token" \
-H 'Content-Type: multipart/form-data; charset=utf-8; boundary=__X_PAW_BOUNDARY__' \
-F "refresh_token=CpCAhcCRtLU4kPjs54omWW3A" \
-F "grant_type=refresh_token"
| Field | Type | Required | Description |
|---|---|---|---|
refresh_token | String | R | The refresh_token obtained in the previous call. |
grant_type | String | R | Fixed value refresh_token. |
{
"access_token": "CE2ZgMjcgcfOvzY0jcS7csYe",
"expires_in": 21600,
"refresh_token": "CdugTgyDDa05uURhK6n6GYiW",
"rt_expires_in": 43200,
"token_type": "bearer"
}
For high-risk PSD2 endpoints (notably POST /openapi/psd2/pisp/v1/payments/{paymentProduct}), an
HMAC-SHA512 signature is mandatory in the request headers. You may also apply the same scheme to every
PSD2 request — DTC will validate when present.
HTTP Method — in uppercase (GET / POST / DELETE).Timestamp — millisecond epoch in Singapore timezone. Requests are rejected if the timestamp drifts by more than 2 minutes.URL — request URL without the scheme and host (e.g. /openapi/psd2/pisp/v1/payments/sepa-credit-transfers).Querystring — in-URL parameters without the leading ?, unencoded; empty string when there are none.Request Body — the exact raw body string, including invisible characters. Empty string for GET / DELETE without a body.GET1636360576641/openapi/psd2/aisp/v1/accounts/details
POST1636360661729/openapi/psd2/pisp/v1/payments/sepa-credit-transfers{"query":{"endToEndId":"INV-001"}}
Sign Key, then Base64-encode.
Sign Key : aR2822Y6XbehWMclnB0Y2NJK
String : POST1636360661729/openapi/test{"a":"124"}
Signature : MxrYnCm9Q7JOAvOrISf8+T2kuTW1d/w0at8aaPaoiX08VWfun3XPokVlIx1TkHXdcitls09wzfUGtXQZq23xdg==
| Header | R/O/C | Description |
|---|---|---|
Authorization | R | Bearer token: Bearer {access_token}. |
Content-Type | R | application/json for JSON body endpoints; multipart/form-data for the OAuth token endpoints. |
D-REQUEST-ID | R | Client-generated unique request id (UUID or any opaque string), echoed in audit logs. |
D-TIMESTAMP | R | Same millisecond timestamp used to build the signature. |
D-SIGNATURE | C | HMAC-SHA512 signature (Base64). Required on PISP payment initiation; recommended on all PSD2 endpoints. |
D-SUB-ACCOUNT-ID | C | Sub-account id under the master account, if you are calling on behalf of one. |
Consent-ID | C | Required on the GET single-transaction endpoint; passed as a header per Berlin Group convention. |
PSU-IP-Address | C | The real PSU's IP — required on AISP endpoints. Do not use the TPP server IP. |
PSU-User-Agent | O | Forwarded to the ASPSP for fraud scoring. |
All PSD2 business endpoints share the standard DTC Open API envelope.
ApiRequest<T>){
"query": { ...endpoint-specific fields... },
"page": { "current": 1, "size": 50 }
}
ApiResponse<T>){
"header": {
"success": true,
"errCode": null,
"errMsg": null
},
"result": { ...endpoint-specific fields... }
}
Top-level header.success | boolean — true only when the call is fully successful. |
Top-level header.errCode | string — a stable code such as PSD2_CONSENT_EXPIRED on failure; null on success. |
Top-level header.errMsg | string — i18n-translated human message. |
result | endpoint-specific object on success. |
| Code | HTTP | Meaning |
|---|---|---|
PSD2_CONSENT_NOT_FOUND | 404 | Consent does not exist or has been revoked. |
PSD2_CONSENT_EXPIRED | 409 | Consent has expired — PSU must grant a fresh consent via SCA. |
PSD2_SCA_REQUIRED | 401 | SCA has not been completed for this consent / payment. |
PSD2_ASPSP_UNAVAILABLE | 503 | Upstream ASPSP is temporarily unreachable. |
PSD2_INVALID_IBAN | 400 | IBAN does not pass format checks. |
PSD2_AMOUNT_LIMIT_EXCEEDED | 400 | Amount exceeds the per-transaction limit configured for the ASPSP. |
PSD2_TOO_MANY_REQUESTS | 429 | Too many requests — client has exceeded the per-consent / per-client rate limit. Retry after the window resets. |
PSD2_SIGNATURE_INVALID | 500 | DTC-side self-check found an inconsistent signature in egress payload. |
PSD2_PAYMENT_NOT_CANCELLABLE | 409 | Payment is in a terminal/settling state and cannot be cancelled. |
PSD2_UNSUPPORTED_PAYMENT_PRODUCT | 400 | Unknown {paymentProduct} in the URL path. |
Base path: /openapi/psd2/v1/consent ·
Required scope: PSD2_AIS
These endpoints manage the AIS consent lifecycle. A PIS consent is created implicitly when initiating a payment — there is no separate "create PIS consent" endpoint.
Create an AIS (Account Information) consent. The response includes an scaRedirectUri that
the wallet client must open in a browser/WebView so the PSU can complete SCA at the ASPSP. Until the
callback fires the consent is in state RECEIVED and cannot be used.
{
"query": {
"scope": "AIS",
"aspspId": "SOMEBANK_DE",
"psuId": "psu-001@example.com",
"ibans": ["DE00000000000000000001"],
"validUntilDays": 90,
"recurringIndicator": true,
"frequencyPerDay": 4,
"tppRedirectUri": "https://wallet.dtcpay.com/openapi/psd2/sca/callback"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
scope | Enum | R | Must be AIS on this endpoint. |
aspspId | String | R | ASPSP identifier issued by DTC for each supported bank. The full list is available in your developer console. |
psuId | String | R | The PSU id at the ASPSP — typically the email or username the PSU uses for online banking. |
ibans | Array<String> | R | IBANs scoped by this consent. |
validUntilDays | Integer | O | Validity in days. Berlin Group RTS caps AIS at 90. Default 90. |
recurringIndicator | Boolean | O | true for ongoing access, false for one-shot. Default true. |
frequencyPerDay | Integer | O | Cap on requests/day (≥1). Berlin Group default 4. |
tppRedirectUri | String | R | The URL the ASPSP will redirect the PSU back to after SCA. |
{
"header": { "success": true },
"result": {
"consentId": "CSNT_A1B2C3D4",
"scope": "AIS",
"aspspId": "SOMEBANK_DE",
"consentStatus": "RECEIVED",
"scaApproach": "REDIRECT",
"scaRedirectUri": "https://psd2.somebank.example.com/sca?consentId=CSNT_A1B2C3D4&state=...",
"ibans": ["DE00000000000000000001"],
"validUntil": "2026-08-13T10:32:11",
"recurringIndicator": true,
"frequencyPerDay": 4
}
}
Return the full metadata snapshot for an existing consent. Cross-tenant access is rejected — only the client that originally created the consent can describe it.
| Name | Type | Description |
|---|---|---|
consentId | String | The consent id returned by the creation call. |
{
"header": { "success": true },
"result": {
"consentId": "CSNT_A1B2C3D4",
"scope": "AIS",
"aspspId": "SOMEBANK_DE",
"consentStatus": "VALID",
"scaApproach": "REDIRECT",
"scaRedirectUri": "https://psd2.somebank.example.com/sca?consentId=...",
"ibans": ["DE00000000000000000001"],
"validUntil": "2026-08-13T10:32:11",
"recurringIndicator": true,
"frequencyPerDay": 4
}
}
Lightweight status check. Use this for polling instead of the full describe endpoint.
{
"header": { "success": true },
"result": {
"consentStatus": "VALID"
}
}
Possible consentStatus values: RECEIVED, VALID,
EXPIRED, REVOKED_BY_PSU, REJECTED, TERMINATED_BY_TPP.
Revoke the consent. Subsequent business calls referencing it will fail with
PSD2_CONSENT_NOT_FOUND.
{
"header": { "success": true },
"result": {
"consentStatus": "REVOKED_BY_PSU"
}
}
Base path: /openapi/psd2/aisp/v1 ·
Required scope: PSD2_AIS
All AISP endpoints require a VALID AIS consent. Refer to §4 for how to obtain one.
List the PSU accounts authorised by the consent. When withBalance=true the ASPSP may
embed the latest balance object in each account; otherwise call POST /accounts/details or
POST /accounts/balances to retrieve balances separately.
{
"query": {
"consentId": "CSNT_K8M3X9P2",
"withBalance": false
}
}
| Field | Type | Required | Description |
|---|---|---|---|
consentId | String | R | A consent in state VALID. |
withBalance | Boolean | O | Berlin Group flag; default false. |
{
"header": { "success": true },
"result": {
"accounts": [
{
"resourceId": "ACC_001",
"iban": "DE00000000000000000001",
"bic": "SBNKDEFFXXX",
"currency": "EUR",
"name": "Sample User Main",
"product": "Current Account",
"cashAccountType": "CACC",
"status": "enabled"
},
{
"resourceId": "ACC_002",
"iban": "DE00000000000000000002",
"bic": "SBNKDEFFXXX",
"currency": "EUR",
"name": "Sample User Savings",
"product": "Savings Account",
"cashAccountType": "SVGS",
"status": "enabled"
}
]
}
}
Return a single account record. When withBalance=true the response also embeds the
latest balance objects (closingBooked, expected, interimAvailable).
{
"query": {
"consentId": "CSNT_K8M3X9P2",
"accountId": "ACC_001",
"withBalance": true
}
}
| Field | Type | Required | Description |
|---|---|---|---|
consentId | String | R | A consent in state VALID. |
accountId | String | R | resourceId returned by /accounts/list. |
withBalance | Boolean | O | Default true. |
{
"header": { "success": true },
"result": {
"account": {
"resourceId": "ACC_001",
"iban": "DE00000000000000000001",
"bic": "SBNKDEFFXXX",
"currency": "EUR",
"name": "Sample User Main",
"product": "Current Account",
"cashAccountType": "CACC",
"status": "enabled"
},
"balances": [
{ "balanceType": "closingBooked", "amount": "1024.50", "currency": "EUR", "referenceDate": "2026-05-15", "lastChangeDateTime": "2026-05-15T10:32:11" },
{ "balanceType": "expected", "amount": "1010.50", "currency": "EUR", "referenceDate": "2026-05-15", "lastChangeDateTime": "2026-05-15T10:32:11" },
{ "balanceType": "interimAvailable", "amount": "1024.50", "currency": "EUR", "referenceDate": "2026-05-15", "lastChangeDateTime": "2026-05-15T10:32:11" }
]
}
}
Return the latest balance objects for a single account.
{
"query": {
"consentId": "CSNT_K8M3X9P2",
"accountId": "ACC_001"
}
}
{
"header": { "success": true },
"result": {
"accountId": "ACC_001",
"balances": [
{ "balanceType": "closingBooked", "amount": "1024.50", "currency": "EUR", "referenceDate": "2026-05-15", "lastChangeDateTime": "2026-05-15T10:32:11" },
{ "balanceType": "expected", "amount": "1010.50", "currency": "EUR", "referenceDate": "2026-05-15", "lastChangeDateTime": "2026-05-15T10:32:11" },
{ "balanceType": "interimAvailable", "amount": "1024.50", "currency": "EUR", "referenceDate": "2026-05-15", "lastChangeDateTime": "2026-05-15T10:32:11" }
]
}
}
| Balance Type | Meaning |
|---|---|
closingBooked | Most recent booked balance at the start of the current business day. |
openingBooked | Booked balance at the start of the previous business day. |
expected | Booked balance plus pending debits (the figure most apps display as "available"). |
authorised | Internal credit-limit indicator. |
interimAvailable | Real-time available balance. |
forwardAvailable | Future-dated available balance. |
Paginated transactions for a single account, filtered by booking status and date range.
{
"query": {
"consentId": "CSNT_K8M3X9P2",
"accountId": "ACC_001",
"bookingStatus": "BOOKED",
"dateFrom": "2026-04-01",
"dateTo": "2026-05-15",
"pageIndex": 1,
"pageSize": 50
}
}
| Field | Type | Required | Description |
|---|---|---|---|
consentId | String | R | A consent in state VALID. |
accountId | String | R | resourceId returned by /accounts/list. |
bookingStatus | Enum | O | One of BOOKED (default), PENDING, BOTH, INFORMATION. |
dateFrom | Date | O | Inclusive ISO date (yyyy-MM-dd). |
dateTo | Date | O | Inclusive ISO date. |
pageIndex | Integer | O | 1-based; default 1. |
pageSize | Integer | O | 1..200; default 50. |
{
"header": { "success": true },
"result": {
"accountId": "ACC_001",
"booked": [
{
"transactionId": "TXN_20260514_001",
"endToEndId": "INV-2026-04-321",
"bookingStatus": "BOOKED",
"bookingDate": "2026-05-14",
"valueDate": "2026-05-14",
"amount": "-150.00",
"currency": "EUR",
"creditorIban": "DE00000000000000000002",
"creditorName": "Sample Creditor Co",
"remittanceInfo": "Invoice 2026-04-321"
},
{
"transactionId": "TXN_20260512_002",
"endToEndId": "SAL-2026-05",
"bookingStatus": "BOOKED",
"bookingDate": "2026-05-12",
"valueDate": "2026-05-12",
"amount": "3200.00",
"currency": "EUR",
"debtorIban": "DE00000000000000000003",
"remittanceInfo": "Salary May 2026"
}
],
"pending": [],
"total": 2,
"pageIndex": 1,
"pageSize": 50
}
}
Return a single transaction by id. The consent id is passed via the Consent-ID header
per Berlin Group convention rather than the request body.
curl -X GET "https://{host}/openapi/psd2/aisp/v1/accounts/ACC_001/transactions/TXN_20260514_001" \
-H "Authorization: Bearer {access_token}" \
-H "Consent-ID: CSNT_K8M3X9P2" \
-H "D-REQUEST-ID: 9b7c4d2a-..."
{
"header": { "success": true },
"result": {
"transactionId": "TXN_20260514_001",
"endToEndId": "INV-2026-04-321",
"bookingStatus": "BOOKED",
"bookingDate": "2026-05-14",
"valueDate": "2026-05-14",
"amount": "-150.00",
"currency": "EUR",
"creditorIban": "DE00000000000000000002",
"creditorName": "Sample Creditor Co",
"remittanceInfo": "Invoice 2026-04-321"
}
}
Base path: /openapi/psd2/pisp/v1 ·
Required scope: PSD2_PIS
The {paymentProduct} URL path segment selects the payment scheme. Phase 0 supports:
| Product code | Description | Required extra fields |
|---|---|---|
sepa-credit-transfers | Standard SEPA Credit Transfer (T+1). | — |
instant-sepa-credit-transfers | SEPA SCT Inst (~10 s); ASPSP must be SCT-Inst capable. | — |
target-2-payments | High-value TARGET2. | creditorAgentBic |
cross-border-credit-transfers | Cross-border (non-SEPA) credit transfer. | creditorAgentBic |
periodic-payments | Standing order; recurring instruction. | startDate, frequency |
Initiate a payment of the given product. The PIS consent is created implicitly with the payment;
the response includes an scaRedirectUri the wallet must open so the PSU can authorise the
payment. Until the SCA callback fires, the payment stays in status RCVD.
This endpoint is idempotency-protected: supply referenceNo for client-controlled
idempotency. If referenceNo is omitted, DTC derives a short-window dedup key from
aspspId + debtorIban + creditorIban + amount + endToEndId so accidental duplicate clicks
are still rejected.
D-SIGNATURE header is mandatory on this endpoint.
{
"query": {
"referenceNo": "INV-2026-04-321",
"aspspId": "SOMEBANK_DE",
"psuId": "psu-001@example.com",
"debtorIban": "DE00000000000000000001",
"creditorIban": "DE00000000000000000002",
"creditorName": "Sample Creditor Co",
"currency": "EUR",
"amount": "150.00",
"remittanceInfo": "Invoice 2026-04-321",
"tppRedirectUri": "https://wallet.dtcpay.com/openapi/psd2/sca/callback",
"endToEndId": "INV-2026-04-321"
}
}
| Field | Type | Required | Description |
|---|---|---|---|
referenceNo | String | O | Idempotency anchor for the anti-duplicate aspect. If omitted, DTC generates one and includes it in the response context. |
aspspId | String | R | ASPSP identifier. |
psuId | String | R | PSU id at the ASPSP. |
debtorIban | String | R | Payer IBAN — must be an account the PSU holds at the ASPSP. |
creditorIban | String | R | Beneficiary IBAN. |
creditorName | String | R | Beneficiary name (max 140 chars; appears on the ASPSP statement). |
creditorAgentBic | String | C | Required for target-2-payments and cross-border-credit-transfers. |
currency | String | R | ISO 4217, 3 chars (e.g. EUR). |
amount | Decimal (string) | R | Positive decimal. Always send as a JSON string to preserve precision (e.g. "150.00"). |
remittanceInfo | String | O | Free-form, max 140 chars. |
tppRedirectUri | String | R | Where the ASPSP returns the PSU after SCA. |
endToEndId | String | R | Reference visible end-to-end on the SEPA rail; serves as a secondary idempotency anchor. |
startDate | Date | C | Required for periodic-payments. |
endDate | Date | O | Optional end date for periodic-payments. |
frequency | String | C | Required for periodic-payments. Berlin Group values: Monthly, Weekly, etc. |
{
"header": { "success": true },
"result": {
"paymentId": "PAY_20260515_A1B2C3",
"transactionStatus": "RCVD",
"scaApproach": "REDIRECT",
"scaRedirectUri": "https://psd2.somebank.example.com/sca?paymentId=PAY_20260515_A1B2C3&state=...",
"psuMessage": "Please complete authentication in your banking app."
}
}
Return the full payment record. Use this when you need debtor/creditor details or the periodic schedule;
for lightweight status polling prefer /status.
curl -X GET "https://{host}/openapi/psd2/pisp/v1/payments/sepa-credit-transfers/PAY_20260515_A1B2C3" \
-H "Authorization: Bearer {access_token}" \
-H "D-REQUEST-ID: 9b7c4d2a-..."
{
"header": { "success": true },
"result": {
"paymentId": "PAY_20260515_A1B2C3",
"paymentProduct": "sepa-credit-transfers",
"transactionStatus": "ACTC",
"debtorIban": "DE00000000000000000001",
"creditorIban": "DE00000000000000000002",
"creditorName": "Sample Creditor Co",
"creditorAgentBic": null,
"currency": "EUR",
"amount": "150.00",
"remittanceInfo": "Invoice 2026-04-321",
"endToEndId": "INV-2026-04-321",
"startDate": null,
"endDate": null,
"frequency": null,
"createdAt": "2026-05-15T10:32:11"
}
}
Return the latest transactionStatus only. Cheap and idempotent — safe to poll on a short
interval. The status reflects the ASPSP's current progression through the payment lifecycle.
{
"header": { "success": true },
"result": {
"paymentId": "PAY_20260515_A1B2C3",
"transactionStatus": "ACSC",
"rejectReasonCode": null,
"rejectReasonMessage": null,
"lastStatusChangeDateTime": "2026-05-15T10:34:22"
}
}
| Status | Meaning |
|---|---|
RCVD | Received by ASPSP, awaiting SCA. |
PDNG | Pending — technical processing in progress. |
ACTC | Accepted Technical Validation. |
ACCP | Accepted Customer Profile checks. |
ACSP | Accepted Settlement In Process. |
ACSC | Accepted Settlement Completed (terminal success). |
ACWC | Accepted With Change (ASPSP adjusted value date etc.). |
ACWP | Accepted Without Posting yet. |
RJCT | Rejected (terminal). See rejectReasonCode. |
CANC | Cancelled (terminal). |
Cancel a payment. Allowed only while the payment has not entered settlement: statuses
ACSP and ACSC return PSD2_PAYMENT_NOT_CANCELLABLE.
{
"header": { "success": true },
"result": {
"paymentId": "PAY_20260515_A1B2C3",
"transactionStatus": "CANC",
"rejectReasonCode": null,
"rejectReasonMessage": null,
"lastStatusChangeDateTime": "2026-05-15T10:36:00"
}
}
{
"header": {
"success": false,
"errCode": "PSD2_PAYMENT_NOT_CANCELLABLE",
"errMsg": "Payment is settled or being settled and cannot be cancelled"
}
}
Base path: /openapi/psd2/callback
state value embedded in the original SCA
redirect URI; calls with a missing or mismatched state are rejected.
Receives the ASPSP redirect after PSU SCA completes, validates the state against the
consent or payment record stored by DTC, and flips the linked consent / payment to
VALID. The wallet front-end can then resume the business flow by polling the consent /
payment status endpoint, or by following the redirectTo URL returned in the JSON
response.
| Name | Type | Required | Description |
|---|---|---|---|
type | Enum | R | PSD2 sub-role being authorised: AIS, PIS, or PIIS. Used for audit logging and to route the state-machine transition. |
aspspId | String | R | ASPSP identifier — echoes the value used when creating the consent / payment. |
id | String | R | The consent id (AIS / PIIS) or payment id (PIS) being authorised. |
code | String | O | OAuth-style authorisation code returned by the ASPSP. Forwarded to the ASPSP token-exchange step; not validated by DTC. |
state | String | R | One-time CSRF state set by DTC when issuing the original SCA URL. Must match exactly. |
GET /openapi/psd2/callback/sca?type=AIS&aspspId=SOMEBANK_DE&id=CSNT_A1B2C3D4&code=AUTH_CODE_xxx&state=2f4a8c9...
# Note: no Authorization header — public endpoint, ASPSP browser redirect.
{
"success": true,
"consentId": "CSNT_A1B2C3D4",
"consentStatus": "VALID",
"redirectTo": "https://wallet.dtcpay.com/openapi/psd2/sca/callback"
}
{
"success": false,
"message": "consent not found or state mismatch",
"id": "CSNT_A1B2C3D4"
}
redirectTo blindly. Validate that the host matches
your registered tppRedirectUri origin before following.