> ## Documentation Index
> Fetch the complete documentation index at: https://docs.services.payward.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Transfers

## 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](/tabs/developer-documentation/get-started/authentication))
* 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:

<Steps>
  <Step title="Create a transfer">`POST /v1/accounts/{account_id}/transfers`</Step>
  <Step title="Poll for status">`GET /v1/transfers/{transfer_id}`</Step>
  <Step title="List and reconcile">`GET /v1/accounts/{account_id}/transfers`</Step>
  <Step title="Cancel (if needed)">`POST /v1/transfers/{transfer_id}/cancel`</Step>
</Steps>

## 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`   | `"finance@globex.com"` | 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

```bash theme={null}
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`)

```json theme={null}
{
  "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"
  }
}
```

<Note>If the response returns `status: completed`, the transfer has already settled — no polling required.</Note>

## 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.

```bash theme={null}
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.

## Metadata

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       |
