PUT {host}/swish-cpcapi/api/v2/paymentrequests/{instructionUUID} | API reference > Payment request v2 > Create Payment Request v2 (E-commerce, M-commerce) | Create the payment request. The path id is a UUID in upper case without hyphens, regex [0-9A-F]{32} (Guidelines, "UUID Description") | payeeAlias (required), payerAlias (optional: set = e-commerce, absent = m-commerce), amount (required, 0.01 to 999999999999.99, "all numbers or with 2-digit decimal separated by a period", sent as a string with two decimals), currency (required, "The only currently supported value is SEK"), callbackUrl (required, HTTPS), payeePaymentReference (optional, a-z A-Z 0-9 -, 1 to 35), message (optional, max 50, letters a-ö A-Ö, 0-9 and !?(),.-:;), callbackIdentifier (optional, regex ^[0-9a-zA-Z-]{32,36}$, returned unchanged as an HTTP header in the callback). Not sent: payerSSN, ageLimit |
| Answer of the create call | same page, "Response" and "Response Codes" | 201 with Location, and PaymentRequestToken for m-commerce; 422 is an array of {errorCode, errorMessage, additionalInformation} | Codes handled: FF08, RP03, BE18, RP01, PA02, AM02, AM03, AM06, RP02, RP06, ACMT03, ACMT01, ACMT07, VR01, VR02, RF07, RP09, TM01; HTTP 400, 401, 403, 415, 429, 500 |
GET {host}/swish-cpcapi/api/v1/paymentrequests/{id} | Payment request v2 > endpoints list (the retrieve and cancel calls of the v2 page are the v1 URLs) and Retrieve Payment Request | Read the state. id = our instructionUUID | Reads id, paymentReference (only when PAID), payeeAlias, amount, currency, status (PAID, DECLINED, ERROR, CANCELLED; an open request is anything else), errorCode, errorMessage; 404 = unknown (real MSS answers RP04) |
PATCH {host}/swish-cpcapi/api/v1/paymentrequests/{id} | Cancel Payment Request | Withdraw a request the payer has not signed | Content-Type application/json-patch+json, body [{"op":"replace","path":"/status","value":"cancelled"}]; 422 RP07 when it can no longer be cancelled |
Callback (POST to callbackUrl) | Guides > Create a payment request > "Handling the callback" | Swish tells us a status changed | Body = payment request object; header callbackIdentifier = the value we sent. Swish retries up to 10 times (5, 10, 20, 40, 60 s) until HTTP 200. The body is only used to find the request: the state always comes from the GET |
| Polling | Guidelines > "Use the callback when creating resources" | Lost callbacks | "If no callback is received within 10 seconds, begin polling the GET endpoint ... start at 10 seconds, then 20, 40, 80": Payments::due() |
| Timeouts | Guides > Create a payment request | Payer has 3 minutes; backend sends ERROR after 5 (e-commerce) / 5.5 (m-commerce) minutes | Countdown on the checkout page (180 s); the cron reads the final state |
PUT {host}/swish-cpcapi/api/v2/refunds/{instructionUUID} | API reference > Refunds v2 > Create Refund | Refund | originalPaymentReference (the paymentReference of the paid request), callbackUrl, payerAlias (the shop's Swish number), amount, currency, message, payerPaymentReference, callbackIdentifier. "Always generate a new UUID for every refund request, even when retrying after a timeout or error." |
GET {host}/swish-cpcapi/api/v1/refunds/{id} | Refunds v2 note "To retrieve the status of the Refund, use the v1 API call" | Read a refund | status CREATED, DEBITED, PAID, ERROR (the guide also names VALIDATED), amount, errorCode; 404 = unknown |
| Refund callback | Guides > Refund a payment | DEBITED within 10 s, then PAID; ERROR at any point | Same header check and read-back as payments |
| Refund error codes | Refunds v2 "Refund error codes" | RF02 (original not found or older than 13 months), RF03, RF06, RF08, RF09, RP09, CD01, RR04, TA01, FF10 ... | Shown to the administrator with a plain-English text |
POST https://mpc.getswish.net/qrg-swish/api/v1/commerce | API reference > QR Codes v1 > Mcom to Qcom | QR image of the m-commerce token | {"format":"png","size":300,"token":...,"border":0,"transparent":false}. The service answers HTTP 406 when the Accept header is not */* (found against the real service) |
swish://paymentrequest?token=<token>&callbackurl=<url-encoded address> | Guides > Trigger the Swish app | App switch on a phone | callbackurl is the URL-encoded address of .back (it carries the request id and a secret key, so the checkout can be picked up in another tab or browser) |
| Hosts | Environments | Production https://cpc.getswish.net, test https://mss.cpc.getswish.net (public test certificate, password swish) | Client certificate: PEM chain + key, sent for this one call from short-lived files |
| TLS trust | Environments and the change log (2025-03-20) | Server certificate chain ends at DigiCert Global Root G2 | The extension bundles that root (src/ca/swish-tls-root-ca.txt) and falls back to the server's own trust store once if the handshake is refused |
| Certificate | Guidelines ("Certificate handling", "Certificate Renewal") | Valid five years; created in the Swish certificate portal; key size 4096 | Upload is checked (key belongs to the certificate, not expired); expiry warning 30 days ahead in the settings page and the log |
| Rate limiting | Change log "HTTP Status 429 Too Many Requests" | 429 with Retry-After | Treated as retryable; the polling schedule keeps calls rare |