Skip to main content

Prerequisites

  • Payward Services API credentials (see Authentication Guide)
  • A verified user with at least one account
Deposit addresses are issued by Payward and managed under /v1/accounts/{account_id}/funds/deposits/addresses. Withdrawals use user-added funding addresses managed under /v1/accounts/{account_id}/funds/addresses; register a destination once and pass its address_id when creating a withdrawal.

Deposits

Deposit workflow

1

List deposit methods

Query available deposit methods for the receiving account and asset.GET /v1/accounts/{account_id}/funds/deposits/methods/{asset_symbol}
2

Prepare the selected method

Fiat and crypto deposits use different preparation steps.

Fiat deposits

Bank transfer: If activation_status is needed, request activation once. If it is pending, wait and list the methods again. When it is completed, not_needed, or omitted, retrieve the bank-transfer instructions. Display every returned field so the user can make the transfer from their bank.Linked bank account: Methods with bank_link in requirements use a linked account instead of bank-transfer instructions. Link the bank account or reuse an active link, then create the deposit to request the funds. Linking alone does not move funds.

Crypto deposits

Deposit address: List existing addresses and reuse a suitable one. If none is available, claim an address. Display the address and any required tag or memo so the user can send the deposit.Bitcoin Lightning: Create an invoice for the exact BTC amount instead of claiming an address. The user must pay it before it expires.
3

Track the deposit

Reconcile deposits on the receiving account through GET /v1/accounts/{account_id}/portfolio/transactions?types=deposit.
The examples below use the signing helpers from the Authentication Guide. For GET requests, sign the same ordered query parameters that you send.
Addresses and memos in the examples are illustrative. Do not send funds to them.
Use Create deposit to pull funds from a linked bank account through a supported deposit method. Currently supported: Plaid US (USD). Discover methods for the receiving account and asset before initiating a deposit.
  1. List deposit methods for the receiving account and asset. Select a supported method whose requirements contains bank_link.
  2. Complete the Bank links flow, or reuse an existing link. The account link must have status: active, and its bank link must have status: linked.
  3. Submit the method’s id and the linked account’s account_link_id to POST /v1/accounts/{account_id}/funds/deposits. Use the same receiving account throughout the flow.
Replace the example identifiers with values returned by discovery and Bank Links. Authenticate the request as described in Authentication. An accepted request returns HTTP 202:
Acceptance does not mean settlement. Poll GET /v1/accounts/{account_id}/portfolio/transactions?types=deposit and match the returned reference to the transaction’s reference.id. The Portfolio transaction id is a separate identifier. Bank-link deposits return a reference.
Create deposit is not idempotent. Do not automatically retry after a timeout or an ambiguous error: the deposit may already have been initiated. Check the account’s transactions and contact Payward Services support if the outcome remains unclear.

Step 1: list deposit methods

Query available deposit methods for an asset. Use the method’s id as method_id when listing deposit destinations or claiming a crypto address. Check requirements on the selected method:
  • []: no additional requirements are reported. Follow the applicable activation and deposit-instructions steps.
  • ["bank_link"]: a linked bank account is required. If you do not already have a suitable link, use Create bank link with the returned method id as method_id, then send the user through the hosted linking flow.
This is a method requirement, not the user’s linking status. It remains bank_link even when the user already has a linked account. Do not infer the requirement from the method name or supports_virtual_accounts. Example USD method excerpts:
For fiat methods, continue when activation_status is not_needed or completed, or when the field is omitted. When it is needed, activate the method once in Step 2. When it is pending, do not send another activation request; list the methods again later or offer another usable method.
Most cryptocurrency deposits are free, with minimum deposit amounts varying by asset. A few cryptocurrencies are charged an address_setup_fee (a one-time fee on the user’s first deposit to a new address) or a per-deposit fee.
Use page_token from next_page_token to request the next page. Omit it for the first page.

Response example

Key fields to display to users are network, method when present, fee, minimum, activation_status, and network_info.est_confirmation_time. Pass the method’s id back as method_id when activating a method, listing deposit instructions, or claiming a crypto address. Optional fee, limit, and network fields are omitted when they do not apply.
For fiat methods, supports_virtual_accounts: true means Funding can provide dedicated virtual-account instructions. false does not identify a particular alternative flow, and omission means Funding did not return deposit metadata for the method. Use the deposit-instructions response, not this boolean, to determine which banking fields and payment reference are available.
Crypto assets can have a maximum of five deposit addresses. Some crypto funding methods share an address space, so the same address can be returned for different assets or networks. method_id selects a context in which the returned address is valid; it does not say how the address was originally claimed. List and reuse an existing address before claiming another.

Step 2: activate a deposit method when required

If the selected method’s activation_status is needed, request activation using its id as method_id. A 204 response means Funding accepted the request; it does not mean activation has necessarily completed, and it does not contain deposit instructions.
After the request is accepted, list deposit methods again. Continue to Step 3 when the selected method reports completed. If it reports pending, wait and list the methods again later.
Activation returns 400 Bad Request when the selected account is missing verification information or documents required by the funding method. The error is associated with account_id; when available, its message names the missing requirement, such as address.
If the activation request times out or its outcome is unclear, list the deposit methods again before taking further action. Do not retry if the activation status is pending or completed.

Step 3: list deposit addresses

Retrieve the crypto addresses or fiat bank-transfer instructions available for the selected funding method. Reuse a returned crypto address instead of creating a new one each time.

Response example

Every item has one address_details variant:
  • crypto.address is required for crypto destinations. crypto.tag and crypto.memo are present only when the network requires them.
  • The fiat object contains only the banking fields that apply to the selected method. Fields such as iban, account_number, routing_number, sort_code, bic, swift, name_on_account, and reference are optional individually. When reference is present, include it with the fiat deposit.
  • expire_time is present only when the destination expires.
Use page_token from next_page_token to retrieve the next page.
Completed deposits appear in GET /v1/accounts/{account_id}/portfolio/transactions?types=deposit. Portfolio visibility is asynchronous.

Step 4: claim a crypto deposit address

If Step 3 returns no suitable crypto address, claim one using the method id from Step 1 as method_id. Fiat deposit methods return their instructions from Step 3 and cannot be claimed with this operation.
You can claim a maximum of five deposit addresses per asset. List the account’s existing addresses before claiming another one.
Address claims are not idempotent. Do not retry automatically after a timeout or another response with an unknown outcome. List the account’s addresses before deciding whether to make another claim.
Some networks (e.g., XRP, XLM) require a tag or memo in addition to the address. If tag or memo is present in the response, your UI must display it and instruct the user to include it when sending funds. Deposits sent without the required tag/memo may be lost.

Bitcoin Lightning invoice flow

For the Bitcoin Lightning deposit method, create a BOLT11 invoice for the exact BTC amount the user intends to deposit. Use the limits from the deposit-methods response to validate the amount before requesting the invoice. The selected account_id is the account that receives the completed deposit.
A Lightning invoice is single-use, must be paid in full, and cannot be paid after expires_at. Invoice creation is not idempotent. If a request has an unknown outcome, create a new invoice; unpaid invoices expire on their own.

Reusable-address UI flow

Best practices

  1. Always display tag/memo: For networks that require a tag or memo (XRP, XLM, etc.), prominently display it alongside the address. Missing tags/memos can result in lost funds.
  2. Set expectations: Show minimum amounts and est_confirmation_time from the methods response so users know what to expect before sending funds.
  3. Use fresh responses: Available methods, addresses and limits are user-specific and may change based on account standing, remaining limits, or regional regulations. Fetch fresh data before displaying options rather than relying on cached results.

Deposit webhook events

Register a webhook through POST /v1/webhooks and subscribe to the deposit lifecycle events your integration needs: All deposit lifecycle events contain type, transaction_id, user_id, and account_id. They can also contain amount and fee:
amount is the total deposit amount, inclusive of the fee. PWS includes it when both the source value and its asset can be resolved. fee is optional. PWS includes it only when the source provides both the fee value and its asset and the asset can be resolved. This includes an explicitly provided zero fee. If the fee or its asset is unavailable, PWS omits fee rather than assuming that it is zero or that it uses the deposit amount’s asset. The availability of amount and fee is independent of the lifecycle event type. Treat absent fields as unavailable; PWS does not return them as null. Returned and failed deposits also contain a required reason field. PWS normalizes it to one of account_details_mismatch, limit_exceeded, duplicate, account_restricted, or other. Other deposit lifecycle events do not contain reason. A deposit can produce multiple lifecycle events as it progresses. Treat each webhook as a notification and use the Portfolio Transactions endpoint for reconciliation. Deliveries can be repeated, so use the svix-id header as the deduplication key and return a 2xx response after accepting the event. These events describe the lifecycle of a deposit. They are distinct from conversion.deposit_* events, which describe the inbound funding leg of a conversion.

Crypto withdrawals

Create a normal crypto withdrawal to a saved funding address. Funding calculates the fee and validates the method, network, destination, limits, activation, account state, and Travel Rule requirements. Quote the fee first when you need to show it to a user before they commit.

Withdrawal workflow

1

List withdrawal methods

Choose a method or network and inspect its required address_fields.GET /v1/accounts/{account_id}/funds/withdrawals/methods/{asset_symbol}
2

Check withdrawal limits

Retrieve the current maximum and rolling limits for each available method.GET /v1/accounts/{account_id}/funds/withdrawals/limits/{asset_symbol}
3

Select a funding address

List and reuse a compatible address_id. Register a destination first when no suitable address exists.GET /v1/accounts/{account_id}/funds/addressesPOST /v1/accounts/{account_id}/funds/addresses
4

Quote the withdrawal fee before you display it

Get the fee for a gross amount, plus the short-lived fee_token you carry into the next step.POST /v1/accounts/{account_id}/funds/fees
5

Create the withdrawal

Submit the selected scope, saved address_id, public asset symbol, and gross amount.POST /v1/accounts/{account_id}/funds/withdrawals
6

Handle address-ownership verification

If the request returns withdrawal_verification_required, complete a supported Travel Rule verification method.
7

Reconcile through Portfolio

Use the returned withdrawal_id as reference.id with reference.kind=funding.
To safely retry a withdrawal after a timeout or another unknown outcome, generate a UUIDv4 Idempotency-Key and reuse the same key for each retry. The header is optional. If you omit it, each request is treated as a new withdrawal request. Exact Portfolio reconciliation requires the withdrawal_id returned by a successful create response.

Step 1: list withdrawal methods

Use each method’s id as scope.method_id, or its network_id as scope.network_id. Network scope succeeds only when Funding can resolve exactly one eligible method for the requested asset. Otherwise, retry with a specific method ID. fee and minimum are informational and can change before submission. To get fee terms for a specific amount that you can carry into withdrawal creation, quote them in Step 4.

Step 2: check withdrawal limits

Retrieve the account-specific limits for the asset after choosing a method. Use only entries whose method_id appears in the withdrawal-methods response for the same account and asset. Compare your intended amount against maximum_amount, and check period_limits too: count-based limits do not reduce maximum_amount, so a withdrawal can still be rejected when maximum_amount looks sufficient. All values are point-in-time and can change before submission. See List withdrawal limits for the full field reference.

Step 3: select or create a funding address

List the account’s funding addresses and reuse a compatible destination. Register a new address only when no suitable address exists.
Funding-address creation is not idempotent. If the request has an unknown outcome, list the account’s funding addresses before creating another one. Do not automatically retry.

List existing funding addresses

The first request can include page_size. To continue, send the returned page_token and the same method_id when filtering. Omit page_size; the token preserves it. The token is bound to the selected account and method filter. Pass method_id to filter by that method’s scope; omitting it returns every funding address on the account. Because scopes nest (method → network → network group), a matching address may be registered more broadly and report a network_id or network_group_id in scope instead of the method_id you filtered on. An empty method_id is rejected as a validation error, not treated as no filter.

Create a funding address

Set exactly one scope:
  • Use method_id when the destination should be registered for one withdrawal method.
  • Use network_id when the destination should be valid for methods on that network.
Funding validates the scope and address fields. Collect the fields identified by address_fields in the withdrawal-method response. Do not add local address-validation rules.
Successful creation returns 200:
The name must be unique per account and is limited to 64 characters. A create request can return these 409 codes: Address limits vary by account and scope and are not exposed by this API. Reuse an existing address or contact support when the limit is reached.

Get, rename, or delete a funding address

Use the stable address_id in the member path:
  • GET /v1/accounts/{account_id}/funds/addresses/{address_id} returns the saved scope, name, and address details.
  • PATCH /v1/accounts/{account_id}/funds/addresses/{address_id} renames the address and returns 204.
  • DELETE /v1/accounts/{account_id}/funds/addresses/{address_id} deletes the address and returns 204.
Get and delete return 404 when the address is absent or unavailable to the selected account. Update can return 403 when the caller is not allowed to change the address. Always enforce account-to-address ownership in your integration.

Step 4: quote the withdrawal fee before you display it

Quote the fee for the gross amount you intend to withdraw. Use a method id from Step 1 as method_id. Fiat methods succeed but omit fee_token, since their fees don’t change between quote and withdrawal. Skip this step when you do not need to show a fee before submitting. amount is the gross amount, inclusive of the fee.
A successful quote returns 201:
net_amount is what reaches the destination, and for same-asset crypto fees net_amount + fee equals gross_amount. Each request returns a new quote and moves no funds. Pass fee_token to Step 5 to reuse this quote’s fee terms. Treat the token as opaque and sensitive: do not parse or modify it, do not log it, and do not reuse it across users or accounts. The quote checks the method and the amount only. Funding still checks balance, method minimums, address compatibility, and Travel Rule requirements when you create the withdrawal.

Step 5: create the withdrawal

amount is the gross amount debited from the account, inclusive of the fee. For same-asset crypto fees, net_amount + fee equals gross_amount. To reuse the fee terms from Step 4, send its fee_token and set scope.method_id to the id of the method you quoted. Fee tokens cannot be used with network scope. Omit fee_token to have Funding calculate the fee when the withdrawal is created. Funding recalculates the absolute fee from the token’s pinned terms and this request’s amount. Submit the same amount as the quote to reproduce the fee you displayed.
The token does not pin the amount. Submitting a different amount does not invalidate the token, but Funding then recalculates the fee for the amount you submit, so the fee charged differs from the fee you displayed. The request is still subject to the usual amount checks. Request a new quote whenever the amount changes.
A 400 on fee_token means no withdrawal was created. Request a new quote and resubmit with its token. Do not resend a rejected token.
Successful withdrawal creation returns 201:

Address-ownership verification

When the response is 409 withdrawal_verification_required, read verification_methods. Funding can return self_attestation, satoshi_test, or digital_signature. The PWS Travel Rule verification endpoint currently accepts self_attestation from this list. Complete it through POST /v1/users/{user_id}/travel-rule/verifications, then submit a new withdrawal request. Contact support when the response does not include a method that the endpoint supports.

Reconcile the withdrawal

List GET /v1/accounts/{account_id}/portfolio/transactions?types=withdrawal. Match the transaction whose reference.kind is funding and whose reference.id equals the returned withdrawal_id. Portfolio is the canonical status and history surface. Do not wait for a withdrawal lifecycle webhook; this API does not publish one.

Withdrawal best practices

  1. Reuse saved addresses: List funding addresses before creating another destination.
  2. Use the exact scope: Prefer method_id when multiple methods exist on the same network.
  3. Quote the fee before you display it: Method-list fees are estimates. Quote the fee for the amount you intend to withdraw, then send that quote’s fee_token with the same amount.
  4. Reuse idempotency keys for retries: Generate a UUIDv4 key before creating a withdrawal. Reuse it after an unknown outcome. If you omit the header, reconcile through Portfolio before submitting another withdrawal.
  5. Protect routing fields: Preserve required tags and memos, and do not log complete destination details.

Common errors

API reference