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

# Quickstart

> Create a collection account, receive a simulated payment, and see the funds credited to your balance - end to end on sandbox real time.

<Note>
  Everything below runs on sandbox, so no real money moves.
</Note>

By the end of this guide you will have provisioned a Virtual Account via API, simulated an incoming bank transfer, received the `collect.succeeded` webhook, fetched the collect, and confirmed the credit on your balance.

You need two things before starting: a [sandbox account](https://dashboard-sandbox.tazapay.com) with API keys ([Get Started with Tazapay](/getting-started/overview/get-started-with-tazapay)) and an entity.

> There is no real onboarding needed on sandbox, you can [create an entity](/api-reference/tazapay-api/create-entity) and [simulate its approval](/api-reference/tazapay-api/simulate-entity-status-in-sandbox) directly.

*This walkthrough uses a Singapore SGD Virtual Account. The identical flow applies to other currencies and stablecoin wallets.*

## The flow at a glance

1. **Provision the account** - `POST /v3/collection_account`
2. **Account enabled** - the enablement request succeeds and `collection_account.status` flips to `enabled`
3. **Fetch account details** - the collection\_account object contains the bank account details
4. **Payer transfers funds** - a normal domestic transfer, or SWIFT, or an on-chain send
5. **Collect created & screened** - Tazapay creates a collect and runs compliance screening
6. **Collect succeeds** - `collect.succeeded` fires
7. **Balance credited** - funds land in your Tazapay balance, converted if needed. Track using the [balance\_transaction](/api-reference/tazapay-api/fetch-balance-transaction) object.

<Steps>
  <Step title="Set up Authentication">
    The Tazapay API uses HTTP Basic authentication: your `API_Key` is the username and your `API_Secret` is the password, joined with a colon, Base64-encoded, and sent as `Authorization: Basic <value>`. See [Authentication](/api-reference/api-overview/authentication) for the full breakdown.

    All calls in this guide use the sandbox base URL. See [Endpoints and Environments](/api-reference/api-overview/endpoints-and-environments).

    ```bash Sandbox base URL theme={null}
    https://service-sandbox.tazapay.com
    ```

    `curl -u` performs the Basic encoding for you, so the examples below stay copy-pasteable:

    ```bash Set your credentials theme={null}
    export TZP_KEY="your_api_key"
    export TZP_SECRET="your_api_secret"
    export TZP_BASE="https://service-sandbox.tazapay.com"
    ```
  </Step>

  <Step title="Discover what you can create (optional)">
    Before creating anything, ask the Metadata API what your account is actually allowed to provision. This returns the payment method types, currencies, rails, and transfer limits available to you.

    ```bash Request theme={null}
    curl -X GET "$TZP_BASE/v3/metadata/collection_accounts/virtual_account?country=SG&currencies=SGD" \
      -u "$TZP_KEY:$TZP_SECRET"
    ```

    ```json Response (trimmed) theme={null}
    {
      "capabilities": [
        {
          "payment_method_type": "local_bank_transfer_sgd",
          "currencies": [
            "SGD"
          ],
          "transfer_limit": {
            "minimum": {
              "amount": 100,
              "ccy": "SGD"
            },
            "maximum": {
              "amount": 100000000,
              "ccy": "SGD"
            },
            "currency": "SGD"
          },
          "local": {
            "fund_transfer_networks": [
              {
                "name": "FAST",
                "additional_information": "Near-instant, 24x7."
              },
              {
                "name": "PayNow",
                "additional_information": "Near-instant, 24x7."
              },
              {
                "name": "MEPS",
                "additional_information": "Same-day on business days."
              }
            ]
          },
          "on_behalf_of": {
            "support": true,
            "additional_requirements": [
              "entity_submission_required"
            ]
          },
          "setup_time": "instant",
          "account_reenablement_supported": true
        }
      ]
    }
    ```

    <Note>
      Sandbox availability may differ from production. In production, what you can provision depends on your onboarding profile — if a corridor you need is missing here, check [Virtual Account coverage](/collection-accounts/coverage/virtual-accounts) and talk to your account manager.
    </Note>

    ### Related Links

    * [Virtual Account Coverage and Features API](/api-reference/tazapay-api/virtual-account-metadata)
    * [Stablecoin Features](/api-reference/tazapay-api/wallet-metadata)

    > This is an optional step; you can skip it if you already know what you can provision.
  </Step>

  <Step title="Create the Collection Account">
    Create a Singapore SGD Virtual Account on the local rail. Only `type` and `payment_method_type` are required by the schema; `country` and `currencies` are additionally required for virtual accounts.

    ```bash Request theme={null}
    curl -X POST "$TZP_BASE/v3/collection_account" \
      -u "$TZP_KEY:$TZP_SECRET" \
      -H "Content-Type: application/json" \
      -d '{
        "type": "virtual_account",
        "payment_method_type": "local_bank_transfer_sgd",
        "country": "SG",
        "currencies": ["SGD"],
        "alias": "quickstart-account",
        "description": "Quickstart test account for SGD collections"
      }'
    ```

    ```json Response theme={null}
    {
      "id": "cva_d2dgk0552psfuj1he0",
      "object": "collection_account",
      "type": "virtual_account",
      "payment_method_type": "local_bank_transfer_sgd",
      "country": "SG",
      "currencies": [
        "SGD"
      ],
      "status": "disabled",
      "alias": "quickstart-account",
      "description": "Quickstart test account for SGD collections",
      "requests": [
        {
          "id": "req_cva001enablement",
          "object": "collection_account_request",
          "collection_account_id": "cva_d2dgk0552psfuj1he0",
          "type": "enablement",
          "status": "processing",
          "requested_currencies": [
            "SGD"
          ],
          "created_at": "2024-09-26T09:39:25.03501Z",
          "updated_at": "2024-09-26T09:39:25.03501Z",
          "status_description": "Activation in progress."
        }
      ],
      "status_description": "",
      "metadata": {},
      "created_at": "2024-09-26T09:39:25.03501Z",
      "updated_at": "2024-09-26T09:39:25.03501Z"
    }
    ```

    Note the account is created with status `disabled` with an `enablement` request attached; it cannot receive funds just yet. The account's `status` is derived from the state of that request, not set directly. For the full request lifecycle and every state a request can pass through, see [Collection Account Status Flow](/collection-accounts/requesting-for-vas/api#collection-account-status-flow).

    Save the returned `id`, every step below uses it:

    ```bash theme={null}
      "cva_d2dgk0552psfuj1he0"
    ```
  </Step>

  <Step title="Wait for enablement">
    <Tabs>
      <Tab title="Webhooks (recommended)">
        Subscribe to `collection_account.creation_succeeded`. It fires when the enablement request succeeds and the status flips to `enabled`.

        ```json collection_account.creation_succeeded (trimmed) theme={null}
        {
          "type": "collection_account.creation_succeeded",
          "id": "evt_crqinqs584jmicmfjbhg",
          "object": "event",
          "created_at": "2024-09-26T09:39:55.369534811Z",
          "data": {
            "id": "cva_d2dgk0552psfuj1he0",
            "object": "collection_account",
            "payment_method_type": "local_bank_transfer_sgd",
            "status": "enabled",
            "currencies": [
              "SGD"
            ],
            "virtual_account": {
              "account_holder_name": "OM Grand Limited",
              "account_number": "0109866363",
              "bank_name": "STANDARD BANK LIMITED",
              "bank_codes": {
                "swift_code": "SLSGO2XXX"
              }
            },
            "created_at": "2024-09-26T09:39:25.03501Z",
            "updated_at": "2024-09-26T09:39:25.03501Z"
          }
        }
        ```

        The same family of events reports the unhappy paths.  `creation_requires_action`, `creation_under_approval_hold`, `creation_failed`, `creation_cancelled`. Handle at least `creation_failed` before going live.

        > Complete list of events: [Collection Account Webhooks](/api-reference/tazapay-api/collection-account-webhooks).

        <Note>
          On setting up and securing your endpoint, see the [Webhooks Guide](/api-reference/appendix/webhooks-guide) and [Webhook Authentication](/api-reference/appendix/webhook-authentication).
        </Note>
      </Tab>

      <Tab title="Polling">
        Poll the collection\_account object periodically until `status` is `enabled`.

        ```bash Request theme={null}
        curl -X GET "$TZP_BASE/v3/collection_account/$CVA_ID" \
          -u "$TZP_KEY:$TZP_SECRET"
        ```

        Once enablement succeeds, the account looks like this — `status: enabled`, and the `enablement` request in `requests` now reads `succeeded`:

        ```json expandable Collection Account — enabled SGD virtual account theme={null}
        {
          "id": "cva_d2dgk0552psfuj1he0",
          "object": "collection_account",
          "type": "virtual_account",
          "payment_method_type": "local_bank_transfer_sgd",
          "country": "SG",
          "currencies": [
            "SGD"
          ],
          "status": "enabled",
          "alias": "quickstart-account",
          "description": "This account is used for SGD collections",
          "virtual_account": {
            "account_holder_name": "OM Grand Limited",
            "account_number": "0109866363",
            "iban": "",
            "bank_name": "STANDARD BANK LIMITED",
            "bank_branch": "8 MARINA BOULEVARD, 27-01, MARINA BAY FINANCIAL CENTRE",
            "bank_address": {
              "address_line_1": "",
              "address_line_2": "",
              "city": "",
              "country": "Singapore"
            },
            "bank_codes": {
              "swift_code": "SLSGO2XXX"
            },
            "account_reenablement_supported": true
          },
          "requests": [
            {
              "id": "req_cva001enablement",
              "object": "collection_account_request",
              "collection_account_id": "cva_d2dgk0552psfuj1he0",
              "type": "enablement",
              "status": "succeeded",
              "requested_currencies": [
                "SGD"
              ],
              "created_at": "2024-09-26T09:39:25.03501Z",
              "updated_at": "2024-09-26T09:39:30.03501Z",
              "status_description": "Account enabled successfully."
            }
          ],
          "status_description": "",
          "metadata": {},
          "created_at": "2024-09-26T09:39:25.03501Z",
          "updated_at": "2024-09-26T09:41:43.349835Z"
        }
        ```

        Field-level reference: [Collection Account object](/api-reference/tazapay-api/global-collection-account-object).
      </Tab>
    </Tabs>
  </Step>

  <Step title="Fetch the account details your payer needs">
    Fetch the collection\_account object and read the `virtual_account` block. These are the coordinates your payer transfers to.

    ```bash Request theme={null}
    curl -X GET "$TZP_BASE/v3/collection_account/$CVA_ID" \
      -u "$TZP_KEY:$TZP_SECRET"
    ```

    ```json Virtual account details to share with your payer theme={null}
    {
      "id": "cva_d2dgk0552psfuj1he0",
      "object": "collection_account",
      "status": "enabled",
      "country": "SG",
      "currencies": [
        "SGD"
      ],
      "payment_method_type": "local_bank_transfer_sgd",
      "virtual_account": {
        "account_holder_name": "OM Grand Limited",
        "account_number": "0109866363",
        "iban": "",
        "bank_name": "STANDARD BANK LIMITED",
        "bank_branch": "8 MARINA BOULEVARD, 27-01, MARINA BAY FINANCIAL CENTRE",
        "bank_address": {
          "address_line_1": "",
          "address_line_2": "",
          "city": "",
          "country": "Singapore"
        },
        "bank_codes": {
          "swift_code": "SLSGO2XXX"
        }
      }
    }
    ```

    The keys present under `bank_codes` vary by country and rail — it may contain `swift_code`, `routing_code`, `sort_code`, `ach_routing_number`, `fedwire_routing_number`, `bsb_code`, or `bank_code`. Read them dynamically rather than assuming a fixed set. Full reference: [Collection Account object](/api-reference/tazapay-api/global-collection-account-object).

    In production, these are the details you display to your customer or print on your invoice. The payer then makes a transfer to this account.
  </Step>

  <Step title="Simulate an incoming payment">
    Sandbox includes a **Collect Simulation** feature so you can mimic an incoming payment without moving real money.

    Go to the [Sandbox dashboard](https://dashboard-sandbox.tazapay.com/) → **Virtual Accounts/Wallets** → **Simulate Collect**, pick the account you just created, and simulate the `succeeded` state.

    You can simulate every intermediate and terminal state, which is how you exercise the unhappy paths in your integration:

    | State flow              | What it exercises                           |
    | ----------------------- | ------------------------------------------- |
    | `succeeded`             | The happy path - funds settled successfully |
    | `on_hold` → `succeeded` | Held for review, then cleared and settled   |
    | `on_hold` → `failed`    | Held for review and rejected                |
    | `failed`                | Collect rejected outright                   |

    Stablecoin wallets add `detected` transitions, since on-chain payments are visible before final confirmation. The complete matrix for both fiat and crypto is on [Simulating Collects on Sandbox](/api-reference/tazapay-api/simulate-collects-on-sandbox).

    <Note>
      Simulated collects also create a real sandbox balance, which you can then use to fund and test payouts end to end.
    </Note>
  </Step>

  <Step title="Receive the collect and confirm the credit">
    **The webhook.** As soon as the collect settles, `collect.succeeded` fires. This is the event your system should treat as the signal that money arrived — note `balance_transaction`, which ties the collect to the ledger entry on your balance.

    ```json expandable collect.succeeded theme={null}
    {
      "type": "collect.succeeded",
      "id": "evt_d30mfcg3obm733raoh7g",
      "object": "event",
      "created_at": "2025-09-10T11:57:38.761234462Z",
      "data": {
        "id": "col_d30mfargpkanp3hrmqhg",
        "object": "collect",
        "amount": 100000,
        "currency": "SGD",
        "status": "succeeded",
        "type": "local_bank_transfer_sgd",
        "payer_details": {
          "name": "John Doe",
          "payer_bank": {
            "account_number": "",
            "name": "",
            "address": null,
            "bank_codes": {
              "swift_code": "sdasd93e"
            }
          },
          "reference_id": "",
          "additional_information": ""
        },
        "destination": "cva_d2dgk0552psfuj1he0",
        "destination_details": {
          "type": "virtual_account",
          "virtual_account": {
            "id": "cva_d2dgk0552psfuj1he0",
            "object": "virtual_account",
            "account_holder_name": "OM Grand Limited",
            "account_number": "0109866363",
            "bank_name": "STANDARD BANK LIMITED",
            "bank_branch": "8 MARINA BOULEVARD, 27-01, MARINA BAY FINANCIAL CENTRE",
            "bank_address": {
              "address_line_1": "",
              "address_line_2": "",
              "city": "",
              "country": "Singapore",
              "postal_code": "",
              "state": ""
            },
            "bank_codes": {
              "swift_code": "SLSGO2XXX"
            },
            "currencies": [
              "SGD"
            ],
            "iban": ""
          }
        },
        "holding_currency": "SGD",
        "balance_transaction": "btr_d30mfcjgpkanp3hrmql0",
        "on_behalf_of": "",
        "metadata": {},
        "created_at": "2025-09-10T11:57:31.967513Z",
        "tracking_details": null
      }
    }
    ```

    > All collect events and their payloads: [Collect Webhooks](/api-reference/tazapay-api/collect-webhook).

    **Fetch the collect.** Take the collect ID from the webhook and fetch it directly:

    ```bash Request theme={null}
    curl -X GET "$TZP_BASE/v3/collect/col_d30mfargpkanp3hrmqhg" \
      -u "$TZP_KEY:$TZP_SECRET"
    ```

    ```json expandable Collect — succeeded USD collect theme={null}
    {
      "status": "success",
      "message": "",
      "data": {
        "id": "col_d2fapsh76og2qj0ej5g",
        "object": "collect",
        "amount": 100000,
        "currency": "USD",
        "holding_currency": "USD",
        "status": "succeeded",
        "type": "wire_transfer",
        "destination": "cva_d2dgk0552psfuj1he0",
        "destination_details": {
          "type": "virtual_account",
          "virtual_account": {
            "id": "cva_d2dgk0552psfuj1he0",
            "object": "virtual_account",
            "account_holder_name": "OM Grand Limited",
            "account_number": "0109866363",
            "bank_name": "STANDARD BANK LIMITED",
            "bank_branch": "8 MARINA BOULEVARD, 27-01, MARINA BAY FINANCIAL CENTRE",
            "bank_address": {
              "address_line_1": "",
              "address_line_2": "",
              "city": "",
              "country": "Singapore",
              "postal_code": "",
              "state": ""
            },
            "bank_codes": {
              "swift_code": "SLSGO2XXX"
            },
            "currencies": [
              "USD"
            ],
            "iban": ""
          }
        },
        "payer_details": {
          "name": "CMC COMPANY",
          "payer_bank": {
            "account_number": "1112019837840",
            "name": "C Bank",
            "address": null,
            "bank_codes": {
              "swift_code": "AJUM7CHBKXXX"
            }
          },
          "reference_id": "",
          "additional_information": "CM Payment for Order 56"
        },
        "balance_transaction": "btr_u7ftrgipu69og2qj1j1pg",
        "on_behalf_of": "",
        "metadata": {},
        "tracking_details": null,
        "created_at": "2025-08-15T03:43:46.980214Z"
      }
    }
    ```

    Field-level reference: [Collect object](/api-reference/tazapay-api/collects).

    Amounts are in the currency's smallest unit - 100000 here is USD 1,000.00.

    The four fields to reconcile against are `status` (`succeeded`), `amount` and `currency` (what arrived), `destination` (which collection account received it), and `balance_transaction` (the ledger entry).

    **Confirm the balance.** Finally, check that the funds are on your balance:

    ```bash Request theme={null}
    curl -X GET "$TZP_BASE/v3/balance" \
      -u "$TZP_KEY:$TZP_SECRET"
    ```

    ```json Response (trimmed) theme={null}
    {
      "status": "success",
      "message": "",
      "data": {
        "available": [
          {
            "amount": "100000",
            "currency": "SGD"
          }
        ],
        "object": "balance",
        "updated_at": "2024-08-20T06:18:11.475605Z"
      }
    }
    ```

    Balance amounts are strings in the currency's smallest unit "100000" is SGD 1,000.00.

    If the incoming currency is not one of your holding currencies, it is converted automatically at the point of credit rather than as a separate step - see [FX](/collection-accounts/incoming-payments/fx).
  </Step>
</Steps>

***

## Going to production

* **Handle compliance holds** — subscribe to `collect.on_hold` and surface held payments rather than treating silence as failure → [Compliance Holds](/collection-accounts/incoming-payments/compliance-holds)
* **Understand the full collect state machine**, including the wallet-only `detected` state → [State Machine](/api-reference/tazapay-api/collect-state-machine)
* **Plan for reversals** when a collect fails after funds have arrived → [Reversals](/collection-accounts/incoming-payments/reversals)
* **Decide your holding currencies** and how FX should behave → [FX](/collection-accounts/incoming-payments/fx) and [Enabling Additional Balance Currencies](/getting-started/core-concepts/enabling-additional-balance-currencies)
* **Review coverage** for the corridors you actually need → [Virtual Accounts](/collection-accounts/coverage/virtual-accounts) and [Stablecoins](/collection-accounts/coverage/stablecoins)
* **Collecting for your customers?** Read [Collections on Behalf Of](/collection-accounts/integration-guides/collections-on-behalf-of) for entity-level attribution
* **Read the use case guide** matching your business ([B2B Collections](/collection-accounts/use-case-guides/b2b-collections), [Financial Institutions](/collection-accounts/use-case-guides/financial-institutions), or [Marketplaces](/collection-accounts/use-case-guides/marketplaces))

***

<CardGroup cols={2}>
  <Card title="Request via Dashboard" icon="table-columns" href="/collection-accounts/requesting-for-vas/dashboard">
    Prefer no code? Provision the same account from the Tazapay dashboard.
  </Card>

  <Card title="Collection Account API Reference" icon="code" href="/api-reference/tazapay-api/create-collection-account">
    Every field, enum, and endpoint for collection accounts.
  </Card>
</CardGroup>
