Skip to main content

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:
1

Create a transfer

POST /v1/accounts/{account_id}/transfers
2

Poll for status

GET /v1/transfers/{transfer_id}
3

List and reconcile

GET /v1/accounts/{account_id}/transfers
4

Cancel (if needed)

POST /v1/transfers/{transfer_id}/cancel

Transfer lifecycle

StatusDescription
pendingTransfer created.
processingTransfer processing. No longer cancellable.
completedTerminal. Funds delivered.
failedTerminal. failure_reason is populated.
cancelledTerminal. 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.
FieldExampleDescription
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

ParameterDescription
statuspending, processing, completed, failed, cancelled
asset_symbolAsset ticker (e.g. USDC)
asset_typeOptional asset classification (e.g. stablecoin)
external_transaction_idLook up by your own primary key
created_after / created_beforeRFC 3339 timestamp range
page_tokenOpaque token from previous response
page_sizeResults 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.

Metadata

Attach optional key/value pairs to transfers for reconciliation and reporting. Three keys have reserved behavior:
KeyPurpose
referenceHuman-readable label, visible to the recipient in statements and dashboards.
external_transaction_idYour primary key (invoice, order ID). Indexed and searchable via GET /v1/accounts/{account_id}/transfers.
purposeBusiness 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 statusCauseRemediation
400 Bad RequestInvalid payload (e.g. zero or multiple destination fields)Set exactly one of account, tag, or email
401 UnauthorizedMissing or invalid API credentialsVerify API-Key and API-Sign headers
404 Not FoundTransfer ID does not existVerify the transfer_id
409 ConflictTransfer not in a cancellable stateOnly pending transfers can be cancelled
429 Too Many RequestsRate limit exceededBack off and retry with exponential delay