Complete payment flow
Follow Walley's full payment lifecycle, from checkout to settlement, with the API calls you need at each stage.
Prerequisitesβ
Before you start, make sure you have:
- API credentials from Merchant Hub, and a bearer token generated from them
- A store set up in the UAT environment, so you can run the whole flow without moving real money
- A notification endpoint that Walley can reach over HTTPS and that answers
200 OK - The endpoints for the environment you are targeting
Every request below goes to UAT. Swap the hostname for production when you are ready.
Payment lifecycle overviewβ
Five phases make up the full payment lifecycle, each with its own integration steps:
The worked example below follows one order of 1 048 SEK through all five phases: a pair of headphones at 999 SEK plus 49 SEK shipping.
Phase 1: Create the checkout sessionβ
When: the customer reaches your checkout page.
Create the session from your backend. You get back a publicToken for rendering the checkout iframe, and a privateId for every later backend call about this session.
The {checkout.id} template in notificationUri resolves to that same privateId. Name the query parameter whatever suits your backend; this example calls it checkoutId. See Templating the URI values for the other variables and which URIs accept them.
- Request
- Response
POST /checkouts HTTP/1.1
Host: api.uat.walleydev.com
Authorization: Bearer bXlVc2VybmFtZTpmN2E1ODA4MGQzZTk0M2VmNWYyMTZlMDE...
Content-Type: application/json
{
"storeId": 123,
"countryCode": "SE",
"reference": "ORDER-2024-12345",
"merchantTermsUri": "https://example.com/terms",
"notificationUri": "https://example.com/api/walley/notify?checkoutId={checkout.id}",
"cart": {
"items": [
{
"id": "PROD-001",
"description": "Wireless Headphones",
"unitPrice": 999.00,
"quantity": 1,
"vat": 25.0
},
{
"id": "SHIP-001",
"description": "Standard Shipping",
"unitPrice": 49.00,
"quantity": 1,
"vat": 25.0
}
]
}
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"privateId": "6f4a9bc3-8d2e-4f1a-9b7c-3e8d2f1a9b7c",
"publicToken": "public-SE-7f1b3d2a2a73d348dfbd17d3965ff1458c249f84c695eac1"
}
}
Use the publicToken to render the checkout iframe. For every property you can send, see Initialize checkout.
Phase 2: Receive the orderβ
When: the customer completes the purchase.
Walley calls your notification endpoint. Answer 200 OK, then read the session back to get the orderId you need for the rest of the flow.
- Notification Walley sends you
- Your call to read the session
GET /api/walley/notify?checkoutId=6f4a9bc3-8d2e-4f1a-9b7c-3e8d2f1a9b7c HTTP/1.1
Host: example.com
The checkoutId here carries the privateId from Phase 1. Answer 200 OK, or Walley retries. See Handle purchase callbacks.
GET /checkouts/6f4a9bc3-8d2e-4f1a-9b7c-3e8d2f1a9b7c HTTP/1.1
Host: api.uat.walleydev.com
Authorization: Bearer bXlVc2VybmFtZTpmN2E1ODA4MGQzZTk0M2VmNWYyMTZlMDE...
Read data.order.orderId from the response and store it. See Acquire information about a Checkout session for the full response.
Treat this callback as the only reliable signal that a purchase completed. Create the order in your system here, not on the browser redirect.
Phase 3: Capture the paymentβ
When: you ship the goods or deliver the service.
Capturing moves the money. Only captured amounts reach your account. You can capture an order with status NotActivated or PartActivated, in full or a part at a time.
The system is eventually consistent. If you capture immediately after the notification arrives, you may get 404 Not Found or 403 Forbidden while the order is still becoming available. Retry with exponential backoff.
- Request
- Response
POST /manage/orders/7890abcd-ef12-3456-7890-abcdef123456/capture HTTP/1.1
Host: api.uat.walleydev.com
Authorization: Bearer bXlVc2VybmFtZTpmN2E1ODA4MGQzZTk0M2VmNWYyMTZlMDE...
Content-Type: application/json
Walley-Idempotency: 03304b06-cb33-4f78-bcea-86cb4b202ba0
{
"amount": 1048.00,
"actionReference": "SHIP-2024-12345",
"items": [
{
"id": "PROD-001",
"description": "Wireless Headphones",
"unitPrice": 999.00,
"quantity": 1,
"vat": 25.0
},
{
"id": "SHIP-001",
"description": "Standard Shipping",
"unitPrice": 49.00,
"quantity": 1,
"vat": 25.0
}
]
}
HTTP/1.1 202 Accepted
Location: /manage/orders/7890abcd-ef12-3456-7890-abcdef123456
Walley answers 202 Accepted and processes the capture asynchronously. Follow the Location header to read the order back.
What to know about captures:
- You can capture the whole order or part of it, for example only the items you have shipped.
- Several partial captures are fine.
- Send the
itemsarray on partial captures so your reconciliation stays accurate. - For B2B customers the
itemsarray is required, so the customer sees the right VAT.
For partial capture, capture by amount, replacing items and error handling, see Capture order.
Phase 4: Refund the orderβ
When: the customer returns something, or you compensate them.
You can only refund what you have already captured. Refund the whole amount or part of it.
- Request
- Response
POST /manage/orders/7890abcd-ef12-3456-7890-abcdef123456/refund HTTP/1.1
Host: api.uat.walleydev.com
Authorization: Bearer bXlVc2VybmFtZTpmN2E1ODA4MGQzZTk0M2VmNWYyMTZlMDE...
Content-Type: application/json
Walley-Idempotency: 7c1f0a52-9e34-4b81-9d0a-2f6b8c4d1e77
{
"amount": 1048.00,
"description": "Full refund, customer cancellation",
"actionReference": "REFUND-2024-12345",
"items": [
{
"id": "PROD-001",
"description": "Wireless Headphones",
"unitPrice": 999.00,
"quantity": 1,
"vat": 25.0
},
{
"id": "SHIP-001",
"description": "Standard Shipping",
"unitPrice": 49.00,
"quantity": 1,
"vat": 25.0
}
]
}
HTTP/1.1 202 Accepted
Location: /manage/orders/7890abcd-ef12-3456-7890-abcdef123456
Walley answers 202 Accepted and processes the refund asynchronously.
What to know about refunds:
- Full refunds, partial refunds, and refunds carrying fees or discounts are all supported.
- Send the
itemsarray on partial refunds so your reconciliation stays accurate. - For B2B customers the
itemsarray is required, so the customer sees the right VAT.
For partial refunds, fees and discounts, replacement articles and error handling, see Refund order.
Phase 5: Reconcile settlementsβ
When: daily or weekly, as part of your bookkeeping.
Settlements normally arrive daily and hold everything you captured, less what you refunded. Read them to match Walley's payouts against your own ledger.
- List settlements
- Settlement transactions
GET /reports/settlements?query=startDate:>=2024-12-01%20AND%20endDate:<=2024-12-04&page=1&perPage=10 HTTP/1.1
Host: api.uat.walleydev.com
Authorization: Bearer bXlVc2VybmFtZTpmN2E1ODA4MGQzZTk0M2VmNWYyMTZlMDE...
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": [
{
"id": "1",
"startDate": "2024-12-01T00:00:00",
"endDate": "2024-12-04T00:00:00",
"storeId": 1,
"totalAmount": 100000.0,
"currency": "SEK",
"captured": 103000.0,
"refunded": -3000.0,
"reference": "2134"
}
]
}
GET /reports/settlements/1/transactions?page=1&perPage=10 HTTP/1.1
Host: api.uat.walleydev.com
Authorization: Bearer bXlVc2VybmFtZTpmN2E1ODA4MGQzZTk0M2VmNWYyMTZlMDE...
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": [
{
"orderId": "7890abcd-ef12-3456-7890-abcdef123456",
"orderNumber": "ORDER-2024-12345",
"type": "Purchase",
"amount": 1048.00,
"currency": "SEK",
"purchaseDate": "2024-12-01",
"invoiceNumber": "11111111"
}
]
}
For query parameters, file formats and reconciliation advice, see Settlements.
Best practicesβ
Security
- Keep API credentials in a secret store, never in source control.
- Call the API over HTTPS, and serve your notification endpoint over HTTPS.
- Restrict who can reach your notification and validation endpoints.
Error handling
- Retry with exponential backoff rather than in a tight loop.
- Log the requests and responses you exchange with Walley, so you can trace an order later.
- Alert on repeated failures instead of letting them queue silently.
Idempotency
- Send
Walley-Idempotencyon every capture, refund, cancel and reauthorize. See Idempotency. - Store the ids of notifications you have processed, so a repeat delivery changes nothing.
- Wrap your own state changes in a database transaction.
Operations
- Capture before the order reaches its
expiresAt, or it expires uncaptured. - Process notifications asynchronously, and answer
200 OKstraight away. - Reconcile settlements on a schedule rather than on demand.
Next stepsβ
You now have an order that goes from checkout to settlement: a session created from your backend, an order created off the notification callback, money captured when you ship, a refund path, and settlement data to reconcile against.
From here:
- Decide how to handle stock. Inventory validation compares three approaches.
- Model your campaigns so refunds still add up. See Handling discounts.
- Work through the go-live checklist before you switch to production.
Related documentationβ
- Initialize checkout, every property you can send when creating a session
- Handle purchase callbacks, retry behavior and the events Walley notifies you about
- Acquire checkout information, the full response and what each status means
- Order lifecycle, how an order moves between statuses
- Capture order and Refund order, the full request schemas
- Settlements, querying and reconciling payouts
- Error codes, what each status code means and what to do about it