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

# Your first transaction

> From application credentials to a completed P2P transfer in the sandbox.

This guide takes you from [application credentials](/authentication/api-keys) to
a completed [P2P](/api-reference/introduction) transfer in the
[sandbox](/access/sandbox). It uses the real endpoints and request shapes, with
placeholder values you replace.

## Prerequisites

* A [registered application](/guides/register-your-application) with sandbox
  credentials: `clientId`, `clientSecret`, and `apiKey`.
* The base URL `https://api.zeam.money/gw/v1` (shared by sandbox and production).
* A server-side environment to hold credentials and make requests.
* At least one wallet in your association (create one with `POST /v1/wallets`).
* Optional: an `https` [webhook](/webhooks/overview) endpoint for asynchronous
  updates.

Throughout, replace `YOUR_CLIENT_ID`, `YOUR_CLIENT_SECRET`, `YOUR_ACCESS_TOKEN`,
and `YOUR_APP_SECRET` with your own values.

<Steps>
  <Step title="Authenticate" icon="key-round">
    Exchange your client ID and secret for a bearer token. This route is public,
    so it does not take the `x-zeam-auth` header.

    ```bash cURL theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    curl -sS -X POST https://api.zeam.money/gw/v1/auth/token \
      -H "Content-Type: application/json" \
      -d '{ "clientId": "YOUR_CLIENT_ID", "clientSecret": "YOUR_CLIENT_SECRET" }'
    ```

    ```json Response theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    {
      "accessToken": "eyJhbGciOiJ...",
      "tokenType": "Bearer",
      "expiresIn": 3599,
      "associationId": "d290f1ee-6c54-4b01-90e6-d701748f0851"
    }
    ```

    Keep the `accessToken`. The association is resolved server-side from the
    token, so every protected request sends only two headers:

    ```http theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    Authorization: Bearer YOUR_ACCESS_TOKEN
    x-zeam-auth: YOUR_APP_SECRET
    ```

    Common errors: `401` means the client ID or secret is wrong; `400` means the
    body is missing a field. See [Authentication](/authentication/overview).
  </Step>

  <Step title="List your wallets" icon="wallet">
    Retrieve the wallets available to your association and pick a source. For an
    own transfer, pick a second wallet as the destination.

    ```bash cURL theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    curl -sS https://api.zeam.money/gw/v1/wallets \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "x-zeam-auth: YOUR_APP_SECRET"
    ```

    ```json Response theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    {
      "data": [
        {
          "id": "66666666-6666-6666-6666-666666666666",
          "walletName": "Treasury USDC",
          "publicKey": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
          "balances": [
            { "assetCode": "USDC", "balance": "1250.0000000" }
          ]
        }
      ],
      "pagination": { "nextCursor": null, "hasMore": false }
    }
    ```

    Each wallet exposes its `id`, `publicKey`, and best-effort on-chain
    `balances`. Use the `id` values as `walletId` and `destinationWalletId`
    below.
  </Step>

  <Step title="Send a P2P transfer" icon="arrow-left-right">
    Create a same-asset transfer between two of your own wallets with
    `POST /v1/payments/p2p/own`. Supply the source `walletId`,
    `destinationWalletId`, and `sendingAssetCode` (a bare asset code — the
    gateway resolves the issuer). To pay a registered beneficiary instead, use
    `POST /v1/payments/p2p/beneficiary` with `beneficiaryId` and
    `paymentDestinationId`.

    ```bash cURL theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    curl -sS -X POST https://api.zeam.money/gw/v1/payments/p2p/own \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "x-zeam-auth: YOUR_APP_SECRET" \
      -H "Content-Type: application/json" \
      -d '{
        "idempotencyKey": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
        "transactionId": "first-tx-001",
        "externalReference": "first-tx-001",
        "walletId": "66666666-6666-6666-6666-666666666666",
        "destinationWalletId": "99999999-9999-9999-9999-999999999999",
        "sendingAssetCode": "USDZ",
        "amount": 25.5
      }'
    ```

    ```json 202 Accepted theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    {
      "transactionRecordId": "d94b0f8a-6d1e-4a2c-9f3b-2a7c1e5d8b90",
      "intentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": "accepted",
      "isIdempotent": false
    }
    ```

    A P2P transfer runs **asynchronously**. The `202` means it was queued, not
    settled. Keep the `transactionRecordId` to track it. Reusing the same
    `idempotencyKey` returns the original result with `isIdempotent: true`.
  </Step>

  <Step title="Confirm the outcome" icon="circle-check">
    Retrieve the transaction to see its current status.

    ```bash cURL theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    curl -sS https://api.zeam.money/gw/v1/transactions/d94b0f8a-6d1e-4a2c-9f3b-2a7c1e5d8b90 \
      -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
      -H "x-zeam-auth: YOUR_APP_SECRET"
    ```

    ```json Response theme={"theme":{"light":"github-light","dark":"one-dark-pro"}}
    {
      "transactionRecordId": "d94b0f8a-6d1e-4a2c-9f3b-2a7c1e5d8b90",
      "type": "p2p",
      "status": "completed",
      "sendingAsset": "USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
      "originalSendAmount": 25.5,
      "stellarTxHash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
      "completedAt": "2026-01-15T10:32:07Z"
    }
    ```

    Rather than polling in a loop, subscribe to [webhooks](/webhooks/events):
    Zeam sends `IntentSuccessful` on success and `IntentFailed` on failure.
    Reconcile the event against this transaction by `transactionRecordId` (or
    your `externalReference`). You can also re-list your wallets to see the
    updated balances.
  </Step>
</Steps>

## Multi-operation transfers

To send multiple same-asset transfers between your own wallets in one atomic
Stellar transaction, use `POST /v1/payments/p2p/own/multi`. All legs settle or
fail together under a single `transactionRecordId`, intent, and webhook
lifecycle. Supply the shared `idempotencyKey`, `transactionId`,
`externalReference`, optional `memo`, and a `transfers[]` array where each
entry has `walletId`, `destinationWalletId`, `sendingAssetCode`, and `amount`.

For non-P2P operations (`/swap` and `/offramp`), submit each individually and
reconcile by its own `transactionRecordId`.

## Next steps

<CardGroup cols={2}>
  <Card title="Off-ramp testing" icon="flask" href="/access/sandbox#off-ramp-testing">
    Simulate successful and failed off-ramps in the sandbox.
  </Card>

  <Card title="Webhooks" icon="webhook" href="/webhooks/overview">
    Receive lifecycle events instead of polling.
  </Card>

  <Card title="API reference" icon="terminal" href="/api-reference/introduction">
    Full request and response shapes for each endpoint.
  </Card>

  <Card title="Moving to production" icon="rocket" href="/access/production-promotion">
    Promote your application when you are ready.
  </Card>
</CardGroup>
