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

# Funding a wallet

> Let a connected user top up their Agentcard wallet from inside your own app.

Each connected user has an Agentcard wallet that backs the cards they create.
When the balance is short, you create a **funding session** and hand the user a
checkout link — they pay with Apple Pay, Google Pay, or card, and the funds land
in their wallet. You build the trigger and (optionally) host the checkout inside
your app; Agentcard runs the payment.

Funding reuses the user's completed [identity verification](/companies/api/identity-verification) —
there's no separate verification step inside checkout. A user who isn't verified
yet is refused with `kyc_required`; run step 2 first, then fund.

Every call is made from your backend with your platform access token, and names
the user with the `user_id` you received when they connected. Each step links to
its page in the [API reference](/companies/api/reference) — full parameters,
responses, error codes, and a live playground.

## Instructions for your agent

Paste this into your coding agent to implement wallet funding. It assumes the
user is already connected and identity-verified (you have their `user_id`).

```text Instructions for your agent theme={null}
You are adding wallet funding for a connected, identity-verified user (you have
their user_id). Implement server-side with your platform token
(Authorization: Bearer <token>); base URL https://api.agentcard.sh.

1. CREATE A FUNDING SESSION
POST /api/v2/wallet/fund
  { "user_id": "<id>", "amount_cents": <int>,
    "payment_method": "apple_pay" | "google_pay" (optional, default apple_pay),
    "link_type": "hosted" | "embedded" (optional, default hosted) }
-> 201 { id, status: "pending", amount_cents, currency, payment_method,
         link_type, checkout_url, expires_at, checkout_style? , fee_cents? }

Pick link_type by where the user is:
  - "hosted"  (default): checkout_url is an Agentcard-hosted page. Relay it
    anywhere — a button, a QR code, a chat message. The payment order is created
    only when the user opens it, so an unopened link costs nothing.
  - "embedded": checkout_url is an in-app link, minted immediately. Load it in a
    WKWebView (iOS) or Android WebView so the user pays without leaving your app.
    Mint it ONLY when the user taps "Add funds" (it places a real order); never
    relay it (link unfurlers can consume it); render it immediately.

2. HANDLE THE 422s (verification-gated)
  - kyc_required        -> user isn't verified; run identity verification, retry.
  - funding_profile_required -> a one-time funding profile is missing; collect it, retry.
  - kyc_transfer_required    -> a one-time carry-over of an existing verification; do it, retry.
  - unsupported         -> the user's verification can't be used (e.g. non-US).
  - amount_out_of_range -> read min_amount_cents / max_amount_cents from the body;
                           don't hardcode limits.

3. SHOW THE CHECKOUT
  - hosted: open/relay checkout_url.
  - embedded: load checkout_url in a WKWebView. On iOS 16+ the Apple Pay button
    renders in-app (Apple Pay on the Web works in WKWebView, NOT in
    SFSafariViewController — use WKWebView). Google Pay works in a modern Android
    WebView; card is always available. No domain verification on your side.
    Optional: append "&only=apple_pay" (or "&only=google_pay") to the checkout_url
    fragment to show a wallet-only sheet with no card form.

4. CONFIRM COMPLETION (source of truth)
Poll GET /api/v2/wallet/fund/<session_id>
-> { status, amount_cents, currency, failure_reason?, completed_at?, ... }
status: pending -> processing -> completed (or failed / expired).
The embedded page also navigates to /fund/success on completion — observe that
navigation to close your WebView — but treat the status endpoint as authoritative.

ERRORS: { error: { code, message, docs } } — branch on code.

TESTING (test-mode credentials only): sandbox clients create TEST orders (never
charged), so you can exercise the full flow end to end before switching to live
keys.
```

## The flow

<Steps>
  <Step title="Create a funding session">
    From your backend, `POST /api/v2/wallet/fund` with the `user_id` and
    `amount_cents`. Choose `link_type`: `hosted` (default) returns an
    Agentcard-hosted page you can relay anywhere; `embedded` returns an in-app
    link you load in a WebView. If the user isn't verified you get
    `422 kyc_required` — send them through
    [identity verification](/companies/api/identity-verification) first. Read
    `min_amount_cents` / `max_amount_cents` off `422 amount_out_of_range` rather
    than hardcoding limits.

    → [Create a funding session](/companies/api/reference/wallet-fund)
  </Step>

  <Step title="Show the checkout">
    **Hosted:** open or relay `checkout_url`; the user pays in their browser.

    **Embedded:** load `checkout_url` in a `WKWebView` (iOS) or Android WebView.
    On **iOS 16+** the Apple Pay button renders in-app and pops the native Apple
    Pay sheet — Apple Pay on the Web is supported in `WKWebView` but **not** in
    `SFSafariViewController`, so use a `WKWebView`. Google Pay works in a modern
    Android WebView, and card is always available. No domain verification is
    needed on your side.

    ```swift theme={null}
    let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
    webView.load(URLRequest(url: checkoutUrl))
    ```

    To present a wallet-only sheet (just the Apple Pay button, no card form),
    append `&only=apple_pay` to the `checkout_url` fragment.

    Mint an embedded session only when the user has actually initiated payment,
    render it immediately, and never relay it — link unfurlers can consume it.
  </Step>

  <Step title="Confirm completion">
    Poll [`GET /api/v2/wallet/fund/{session_id}`](/companies/api/reference/wallet-fund-status)
    until `completed`. That endpoint is the source of truth for money; treat any
    client-side signal as advisory. The embedded page also navigates to
    `/fund/success` when payment completes, which you can observe to close your
    WebView.

    → [Get a funding session](/companies/api/reference/wallet-fund-status)
  </Step>
</Steps>

## Status values

| Status       | Meaning                                                                       | What to do                                                                 |
| ------------ | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `pending`    | Waiting for the user to open the link and pay.                                | Hosted: show `checkout_url`. Embedded: keep the WebView link you rendered. |
| `processing` | Paid — the deposit is settling.                                               | Wait; poll again.                                                          |
| `completed`  | Funds are in the wallet.                                                      | Done.                                                                      |
| `failed`     | The payment failed (`failure_reason` says why).                               | Create a new session.                                                      |
| `expired`    | The link went unused within its window, or payment was started and abandoned. | Create a new session.                                                      |

## Testing in test mode

With a test-mode credential the whole flow runs against a test environment —
sandbox clients create TEST orders that are never charged, so you can exercise
create → checkout → `completed` end to end (including the embedded WebView flow)
before switching to live keys. On a physical device, cards must be in the
platform wallet; simulators can't show the Apple Pay sheet.
