The Payment Initiation Service (PIS) of Klarna's XS2A v2 (Berlin Group openFinance) PSD2 API — supported payment products, the single-payment initiation flow, request structure, status model and what is not supported.
5 min read
The Payment Initiation Service (PIS) lets a licensed PISP initiate a credit transfer from the customer's payment account, once the customer has approved it through Strong Customer Authentication. Access requires the PSP_PI role in your certificate (see Authentication).
What we support
The PIS exposes single payment initiation and the operations to track an initiated payment:
Operation
Endpoint
Notes
Initiate payment
POST /v2/payments/{payment-product}
Creates a single payment and returns a paymentId.
Payment status
GET /v2/{payment-service}/{payment-product}/{paymentId}/status
Returns the current transactionStatus.
Retrieve payment
GET /v2/{payment-service}/{payment-product}/{paymentId}
Returns the submitted payment details and status.
For the status and retrieve operations the {payment-service} segment is payments.
Not supported
The following parts of the Berlin Group standard are not offered by this API:
pain.001 / XML encoding — only JSON request bodies are accepted. Requests with a pain.001-* product or XML payload are rejected.
Bulk payments (bulk-payments) and periodic payments / standing orders (periodic-payments) — initiation is not available; only single payments can be created.
Payment cancellation — there is no DELETE operation on a payment resource.
Other Berlin Group payment products — target-2-payments and cross-border-credit-transfers are not offered; a request for them returns 404 PRODUCT_UNKNOWN (400 SERVICE_INVALID on the authorization endpoints). Use one of the products in Payment products.
The {payment-product} path segment selects the scheme. The supported JSON products are:
{payment-product}
Scheme
Currency
sepa-credit-transfers
SEPA Credit Transfer (SCT)
EUR
instant-sepa-credit-transfers
SEPA Instant Credit Transfer (SCT Inst)
EUR
se-domestic-credit-transfers
Swedish domestic credit transfer
SEK
sepa-credit-transfers is the default and most widely used product. se-domestic-credit-transfers identifies accounts with bban (20 digits) instead of iban, and the customer must have an SE/SEK account. Any other {payment-product} returns 404 PRODUCT_UNKNOWN on initiation, status and retrieve, and 400 SERVICE_INVALID on the authorization endpoints.
How a payment is initiated
1.
Initiate — POST /v2/payments/{payment-product} with the payment body. The response returns a paymentId, an initial transactionStatus of RCVD, and a _links object with self, status and startAuthorisation.
2.
Authorize — POST to the startAuthorisation link with the PSU-ID (the customer's email) and PSU-IP-Address headers, then poll the scaStatus link while the customer approves in the Klarna app. See SCA for the full flow. The payment is only forwarded for execution once SCA succeeds.
3.
Track — poll the status endpoint (or use the retrieve endpoint) until the payment reaches a final transactionStatus (ACTC or RJCT).
Request structure
A single payment body follows the Berlin Group openFinance 2.x credit-transfer model. Besides the body, every request needs X-Request-ID (a UUID) and, on initiation, PSU-IP-Address. The fields are:
Field
Required
Description
debtorAccount
No
The customer's account the funds are debited from, as an account reference (iban, or bban for se-domestic-credit-transfers). Optional: if omitted, it is resolved after authorization, but only when the customer has exactly one eligible account. Send debtorAccount whenever the customer may hold more than one account.
creditorAccount
Yes
The beneficiary account the funds are credited to, as an account reference (for example, iban).
creditor
Yes
The beneficiary party; creditor.name is required.
instructedAmount
Yes
The amount to transfer, as { currency, amount }.
remittanceInformationUnstructured
No
Free-text reference shown to the beneficiary (array with exactly one entry when present).
paymentIdentification.endToEndId
No
Your own reference, echoed end-to-end.
creditorAgent
No
Object { "financialInstitutionId": { "bicfi": "…" } }. Accepted, but currently ignored.
(The debtor IBAN is the John Doe account from the sandbox test data; IBANs must carry valid check digits, otherwise the request is rejected with 400 FORMAT_ERROR. In production use the customer's and beneficiary's real account references.)
POST to the startAuthorisation link to have the customer authorize the payment — see SCA. The response also lists the available scaMethods.
Payment status
The status endpoint returns a transactionStatus from the ISO 20022 / Berlin Group code list. A payment goes RCVD → PDNG → ACTC or RJCT; no other status is set today:
transactionStatus
Meaning
RCVD
Received — payment created, awaiting authorization.
PDNG
Pending — the authorization has started and the customer has not answered yet.
ACTC
Accepted technical validation — the customer approved the payment. This is the final success status.
RJCT
Rejected — the customer rejected the payment, the SCA window elapsed, or the debtor account could not be used. This status carries no reason fields.
The other Berlin Group statuses (ACCP, ACSP, ACSC, ACWC, CANC) are never returned, so do not wait for ACSC.
Verification of Payee (VOP) — planned
Coming soon
The initiation request accepts the optional Client-VOP-Requested header, but no payee verification is performed yet and the RVCM status is never returned.
Once available, you set the Client-VOP-Requested header on the initiation request; when a payee verification was performed and the names did not match, the response will carry a RVCM status together with the match outcome (creditorNameMatch, matchedCreditorName) so you can confirm with the customer before they authorize.
Errors
Errors are returned as {"apiClientMessages":[{"category","code","text"}]}. Common cases include 400 FORMAT_ERROR for a malformed body, 404 PRODUCT_UNKNOWN for an unsupported product, 401 for certificate/role problems, and 409 for resource state conflicts. See Authentication for certificate and role errors.