Withdrawal
On this page
Send money from your Payout balance to a bank account. Withdrawals use the M2M Withdrawals API (API v2): a separate mTLS host, your QWAC certificate for the connection and a QSEAL signature on every request that creates or cancels a withdrawal.
Before you begin
- Approved QWAC and QSEAL certificates. Get them from a supported Qualified Trust Service Provider (currently I.CA and Disig), import both with
POST /api/v1/mtls/certificatesand wait until Payout approves them. Certificates describes the whole process. - An API key, as in Simple payment, step 1.
- A Bearer token, as in Simple payment, step 2. Get it from the standard host (
https://sandbox.payout.one), not from the mTLS host.
Steps
-
Prepare and sign the request
Prepare the body and sign it with your QSEAL certificate:
Command LineBODY='{ "amount": 300, "currency": "EUR", "external_id": "PAYOUT-2026-0001", "iban": "SK3112000000198742637541", "customer": { "first_name": "John", "last_name": "Doe", "email": "[email protected]" }, "statement_descriptor": "Simple statement description" }' DIGEST="SHA-256=$(printf %s "$BODY" | openssl dgst -sha256 -binary | base64)" JWS_SIGNATURE="<detached JWS over $DIGEST, made with your QSEAL key>"amountis in cents: 300 is 3.00 EUR. The same applies to other currencies, so 30000 is 300 CZK.Digestis the SHA-256 of the exact body you send.X-JWS-Signatureis a detached JWS over theDigestvalue, made with the private key of your QSEAL certificate. Its protected header carries the thumbprint of the QSEAL certificate (x5t#S256) and the signing time (sigT), which must be within 5 minutes of the server time. M2M Withdrawals shows the full header and a signing example.Note
API v1 required a
signatureand anoncein the body. With QSEAL they are no longer needed: the QSEAL signature covers the whole body. -
Create the withdrawal
Send the request to the mTLS host. The connection presents your QWAC; the request carries the Bearer token and the QSEAL headers from step 1.
Command Linecurl --location --request POST 'https://api-mtls-sandbox.payout.one/api/v2/withdrawals' \ --cert qwac.pem --key qwac.key \ --header 'Content-Type: application/json' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer SFMyNTY.EXAMPLE-TOKEN.dGhpcy1pcy1hLWZha2Utc2lnbmF0dXJlLWV4YW1wbGU' \ --header 'Idempotency-Key: 9df1a34b-0c34-4565-bde8-50dd17b336f3' \ --header "Digest: $DIGEST" \ --header "X-JWS-Signature: $JWS_SIGNATURE" \ --data "$BODY"A successful call returns
201 Createdwith the withdrawal:JSON{ "id": 52331, "object": "withdrawal", "amount": 300, "api_key_id": 42, "currency": "EUR", "external_id": "PAYOUT-2026-0001", "iban": "SK3112000000198742637541", "idempotency_key": "9df1a34b-0c34-4565-bde8-50dd17b336f3", "status": "pending", "metadata": {}, "statement_descriptor": "Simple statement description", "created_at": 1759744800, "nonce": "ZUc0Mk9sVXZDOXNsdklzMQ", "customer": { "first_name": "John", "last_name": "Doe", "name": "John Doe", "email": "[email protected]", "phone": null, "note": null }, "signature": "54476b2fc64161ed45036ec6a35a8f8d6b07e13f4d93b24c6247cf6dbbacd68c" }Sending the same
Idempotency-Keyagain returns the existing withdrawal instead of creating a new one.Responses in API v2 are still signed as in API v1. To check that a response comes from Payout, compute the signature from the response values and compare it with
signature.external_idis an empty string when it isnull.TEXTPattern: amount|currency|external_id|iban|nonce|client_secret Input: 300|EUR|PAYOUT-2026-0001|SK3112000000198742637541|ZUc0Mk9sVXZDOXNsdklzMQ|q3dpHpYtDrH-KmGD4HMn5OTEx6IsZPBokQ8CqMONWqMSEePWy9bXd3Ua3KvO7f6C SHA-256: 54476b2fc64161ed45036ec6a35a8f8d6b07e13f4d93b24c6247cf6dbbacd68cNote
The hash is in lowercase hex. Some libraries return uppercase hex; convert it to lowercase before you compare it.
-
Check the status
Reading a withdrawal needs the QWAC and the Bearer token, but no QSEAL signature.
Command Linecurl --location --request GET 'https://api-mtls-sandbox.payout.one/api/v2/withdrawals/52331' \ --cert qwac.pem --key qwac.key \ --header 'Accept: application/json' \ --header 'Authorization: Bearer SFMyNTY.EXAMPLE-TOKEN.dGhpcy1pcy1hLWZha2Utc2lnbmF0dXJlLWV4YW1wbGU'Status Meaning pendingCreated, not processed yet in_transitSent to the bank, not confirmed yet paidPaid out canceledCancelled, not paid out failedFailed, not paid out -
Cancel the withdrawal if needed
You can cancel only a withdrawal that is still
pendingand hasn't been passed to the bank yet. Check if withdrawal can be cancelled tells you in advance whether this is still possible.Sign the cancel request with QSEAL as in step 1. It has no body, so
Digestis the SHA-256 of an empty body.Command LineDIGEST="SHA-256=$(printf %s "" | openssl dgst -sha256 -binary | base64)" JWS_SIGNATURE="<detached JWS over $DIGEST, made with your QSEAL key>" curl --location --request POST 'https://api-mtls-sandbox.payout.one/api/v2/withdrawals/52331/cancel' \ --cert qwac.pem --key qwac.key \ --header 'Accept: application/json' \ --header 'Authorization: Bearer SFMyNTY.EXAMPLE-TOKEN.dGhpcy1pcy1hLWZha2Utc2lnbmF0dXJlLWV4YW1wbGU' \ --header "Digest: $DIGEST" \ --header "X-JWS-Signature: $JWS_SIGNATURE"
In production, use https://app.payout.one for the Bearer token and https://api-mtls.payout.one for the withdrawal calls.
Next steps
- Create withdrawal and the other operations in the API reference list all parameters, responses and errors.
- M2M Withdrawals covers Verification of Payee and the HTTP error codes.
- Need help? Contact support.
- Questions? Contact sales.
- Service status? status.payout.one.
- LLM? Read llms.txt.