Overview
The Transfers API moves funds between PWS accounts. You can send to a destination by account ID, username tag, or email. Same-asset transfers settle synchronously, while transfers held for compliance review progress asynchronously.
Prerequisites:
- Payward Services API credentials (see the Authentication guide)
- A funded PWS account with sufficient balance in the send asset
- Base URL:
https://api.services.payward.com
Workflow
A typical integration follows four steps:
Create a transfer
POST /v1/accounts/{account_id}/transfers
Poll for status
GET /v1/transfers/{transfer_id}
List and reconcile
GET /v1/accounts/{account_id}/transfers
Cancel (if needed)
POST /v1/transfers/{transfer_id}/cancel
Transfer lifecycle
| Status | Description |
|---|
pending | Transfer created. |
processing | Transfer processing. No longer cancellable. |
completed | Terminal. Funds delivered. |
failed | Terminal. failure_reason is populated. |
cancelled | Terminal. Cancelled while still pending. |
Same-asset transfers between PWS accounts typically return completed immediately. Compliance-held transfers return pending and progress asynchronously.
Destination types
The to object is polymorphic: set exactly one of the following fields. Setting zero or more than one returns 400 Bad Request.
| Field | Example | Description |
|---|
account | "ACC-00002" | Direct transfer by PWS account ID |
tag | "@globex-treasury" | Transfer by PWS username tag |
email | "[email protected]" | Transfer by recipient email |
Creating a transfer
Send a POST to /v1/accounts/{account_id}/transfers. Include an Idempotency-Key header (UUIDv4) for safe retries; replayed responses include the Idempotent-Replayed: true header.
cURL example
curl -X POST "https://api.services.payward.com/v1/accounts/NL00KRAK0123456789/transfers" \
-H "API-Key: $PWS_API_KEY" \
-H "API-Sign: $PWS_API_SIGN" \
-H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{
"from": {
"asset": {
"symbol": "USDC",
"type": "stablecoin",
"amount": "50000.00"
}
},
"to": { "account": "ACC-00002" },
"metadata": {
"reference": "Q2-settlement-april",
"external_transaction_id": "INV-2026-04-0042",
"purpose": "settlement"
}
}'
Response (201 Created)
{
"data": {
"id": "txfr_8f3a2b1c4d5e6f7a",
"status": "completed",
"from": {
"asset": { "symbol": "USDC", "name": "USD Coin", "type": "stablecoin", "amount": "50000.00" }
},
"to": { "account": "ACC-00002" },
"fee": { "symbol": "USDC", "name": "USD Coin", "type": "stablecoin", "amount": "0.00" },
"metadata": {
"reference": "Q2-settlement-april",
"external_transaction_id": "INV-2026-04-0042",
"purpose": "settlement"
},
"created_at": "2026-04-23T14:30:00Z",
"completed_at": "2026-04-23T14:30:00.123Z"
}
}
If the response returns status: completed, the transfer has already settled — no polling required.
Polling for status
If the create response returns status: pending, poll GET /v1/transfers/{transfer_id} until the status reaches completed, failed, or cancelled. Alternatively, subscribe to transfer webhooks for real-time updates.
curl -X GET "https://api.services.payward.com/v1/transfers/txfr_8f3a2b1c4d5e6f7a" \
-H "API-Key: $PWS_API_KEY" \
-H "API-Sign: $PWS_API_SIGN"
Listing transfers
GET /v1/accounts/{account_id}/transfers returns results in reverse chronological order with opaque page-token pagination. next_page_token is absent on the final page.
Query parameters
| Parameter | Description |
|---|
status | pending, processing, completed, failed, cancelled |
asset_symbol | Asset ticker (e.g. USDC) |
asset_type | Optional asset classification (e.g. stablecoin) |
external_transaction_id | Look up by your own primary key |
created_after / created_before | RFC 3339 timestamp range |
page_token | Opaque token from previous response |
page_size | Results per page (default 20, max 100) |
Cancelling a transfer
POST /v1/transfers/{transfer_id}/cancel cancels a transfer still in pending status. Transfers that have progressed beyond pending return 409 Conflict. Include an Idempotency-Key header.
Attach optional key/value pairs to transfers for reconciliation and reporting. Three keys have reserved behavior:
| Key | Purpose |
|---|
reference | Human-readable label, visible to the recipient in statements and dashboards. |
external_transaction_id | Your primary key (invoice, order ID). Indexed and searchable via GET /v1/accounts/{account_id}/transfers. |
purpose | Business category: settlement, refund, payout, payroll, treasury, fees, other. |
Additional partner-defined keys are accepted: at most 20 entries, keys matching ^[a-zA-Z0-9_]{1,40}$, values as strings up to 500 characters.
Error handling
| HTTP status | Cause | Remediation |
|---|
400 Bad Request | Invalid payload (e.g. zero or multiple destination fields) | Set exactly one of account, tag, or email |
401 Unauthorized | Missing or invalid API credentials | Verify API-Key and API-Sign headers |
404 Not Found | Transfer ID does not exist | Verify the transfer_id |
409 Conflict | Transfer not in a cancellable state | Only pending transfers can be cancelled |
429 Too Many Requests | Rate limit exceeded | Back off and retry with exponential delay |