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

> ## Agent Instructions
> When building application code, use `@naturalpay/sdk` for TypeScript or `naturalpay` for Python.
> When searching Natural documentation, use the docs MCP at `https://docs.natural.com/mcp`.
> Use the Natural CLI for terminal and CI automation.
> Start integration development and testing in the sandbox. Do not use production unless the user explicitly requests it.
> For sandbox requests that require `customerPartyId`, list customers first. Reuse only the intended fixture; otherwise create a customer.
> REST and SDK amounts use integer minor units. Payments MCP amounts use decimal strings with a required currency code.

# Use Natural as a card vault

> Collect a user's card with one phone code, no email and no identity check, then let your agent pay with it

If all you need is your user's card, use Natural as a card vault. The user enters one code we text
them, adds their card, and they're done. No email, no password, no identity check. When your agent
wants to buy something, the user approves that purchase, and your agent pays through the
[browser proxy](/guides/concepts/browser-tokens) without ever seeing the card number.

If your agent also needs to hold or move money for the user, use a normal
[invitation](/guides/connect/invite-customer) instead. The user signs up with email and verifies
their identity.

You need an [API key](/api-reference/authentication#api-keys) to invite users and an
[agent key](/guides/concepts/agent-keys) for card sessions. Apps connected through Natural OAuth,
such as MCP clients, can't be granted `saved_cards.use`, so they can't run this flow.

## How it works

<Steps>
  <Step title="Invite the user by phone">
    Create an invitation for the user's phone number that asks only for card access.
  </Step>

  <Step title="Send them the link with ?signup=card">
    The user enters a code, their name, and their card. Your agent is connected as soon as the card
    is saved.
  </Step>

  <Step title="Open a card session for each purchase">
    Send the user the approval link with `?signin=phone`. They enter a code, check the purchase, and
    approve it with the card's security code.
  </Step>

  <Step title="Claim and check out">Claim the session and pay through the proxy.</Step>
</Steps>

## 1. Invite the user by phone

Call [`POST /customers/invitations`](/api-reference/customers/invite-customers) with a phone
recipient. Ask for these permissions and nothing else:

| Permission | What it's for |
| - | - |
| `saved_cards.use` | Open card sessions. Required for phone signup. |
| `wallets.read` | List the user's saved cards. |
| `payments.read` | Check a card session's status. |

`party.read` is also allowed. Any other permission, or `{"type":"ALL"}`, needs a full account:
the user can't accept it with a phone code.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import Natural from "@naturalpay/sdk";

  const client = new Natural();
  const invitations = await client.customers.createInvitations({
    recipients: [{ type: "phone", value: "+14155550123" }],
    agents: [
      {
        agentId: "agt_019cd1798d637a4da75dce386343931d",
        permissions: ["saved_cards.use", "wallets.read", "payments.read"],
      },
    ],
    redirectUrl: "sms:+14155550199",
  });

  const invitation = invitations.data[0];
  const link = `${invitation.attributes.url}?signup=card`;
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.natural.com/customers/invitations \
    -H "Authorization: Bearer $NATURAL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "data": {
        "attributes": {
          "recipients": [{ "type": "phone", "value": "+14155550123" }],
          "agents": [{
            "agentId": "agt_019cd1798d637a4da75dce386343931d",
            "permissions": ["saved_cards.use", "wallets.read", "payments.read"]
          }],
          "redirectUrl": "sms:+14155550199"
        }
      }
    }'
  ```
</CodeGroup>

* **One agent per invitation.** Each agent gets its own invitation (`adi_*`), and the link
  connects only that one.
* **`redirectUrl`** is optional. It sends the user back to you after they save the card: an
  `https` URL, an app deep link, or an `sms:` link back to a chat.
* **Expiry.** Invitations last 30 days unless you set `expiresAt` (up to 90). The user must sign up
  before then.

## 2. Send the user the link

Natural doesn't send phone invitations. Add `?signup=card` to the invitation's `url` and send it
yourself, wherever you talk to the user: a text, a chat, your app.

```text theme={null}
https://www.natural.com/connect/adi_019cd1798d96adc082e235b426d4e04c?signup=card
```

Without `?signup=card`, the link starts a normal signup with email and an identity check.

### What the user sees

1. **Sign up.** "Create an account with the phone number ending in 0123" and **Continue with
   phone**. There's no email or Google option. They never type the number: we text the code to the
   number you invited.
2. **Enter the code.**
3. **Approve your agent.** They see your app and what it's asking for.
4. **Enter their name.**
5. **Add their card.** The page reads "Add a card for Acme", with your app's name. They enter the
   card number, expiry and security code, and tap **Save card**. Natural stores the card number
   encrypted and never stores the security code.
6. **Done.** "Your card is saved". If you set `redirectUrl`, they go there next.

If the number already belongs to a Natural account, the same screen signs them in instead, and
they go straight to adding their card.

### Know when they're done

The connection is live once the card is saved. You get the
`agent_delegation_invitation.accepted` and `delegation.activated` webhooks, and the user appears
in [`GET /customers`](/api-reference/customers/list-customers). Their `id` (`pty_*`) is the
`customerPartyId` you pass from now on.

## 3. Open a card session for each purchase

Find the card with `GET /card-external-accounts?customerPartyId=pty_…`, then open a session with
[`POST /card-sessions`](/api-reference/card-sessions/create-card-session). Call it with your
agent's key and an `X-Instance-ID` header.

```bash cURL theme={null}
curl https://api.natural.com/card-sessions \
  -H "Authorization: Bearer $NATURAL_AGENT_KEY" \
  -H "X-Instance-ID: $(uuidgen)" \
  -H "Idempotency-Key: order_8812" \
  -H "Content-Type: application/json" \
  -d '{
    "data": {
      "attributes": {
        "customerPartyId": "pty_019cd1798d637a4da75dce386343931d",
        "cardId": "eac_019cd17b2e5f7c1a9b3d4e6f8a0b2c4d",
        "allowedHosts": ["api.stripe.com"],
        "purchase": { "merchantName": "Acme Store", "amount": 4999, "currency": "USD" }
      }
    }
  }'
```

The response has an `approvalUrl`. Add `?signin=phone` and send it to the user:

```text theme={null}
https://www.natural.com/dashboard/card-approvals/QO9J1KqnWOZT5dY6W7sT5w?signin=phone
```

<Warning>
  Always add `?signin=phone` for a user who signed up by phone. Without it, a signed-out user is
  sent to the normal sign-in page, which asks for email or Google. A phone-only user has neither.
</Warning>

### What the user sees

1. **Sign in**, if they're signed out. We text them a code. They enter it and stay on the
   approval page.
2. **Check the purchase.** "Your agent is asking to pay", with the amount, merchant, card and the
   hosts that receive the card.
3. **Approve.** They enter the card's security code and tap **Approve**, or tap **Decline**.

The user must approve, and your agent must claim, within 10 minutes of opening the session. If the
session expires, open a new one and send a new link.

## 4. Claim and check out

Poll [`GET /card-sessions/{sessionId}`](/api-reference/card-sessions/get-card-session) until
`status` is `approved`. Then
[claim it](/api-reference/card-sessions/claim-card-session) and check out through the proxy. See
[Browser tokens](/guides/concepts/browser-tokens) for the claim and proxy setup.

## What a phone-only user can do

Signing in with a phone code gives a limited session. The user can manage their saved cards,
approve card purchases, and accept or remove card-only agent connections. Anything else, such as
moving money or changing account details, asks them to sign in with email or Google, which a
phone-only user doesn't have yet.

Phone-only users can't use [agent tokens](/guides/concepts/agent-tokens). `requestAgentToken` has
no effect for them: pay through the proxy.

## Limits

* **Production only for now.** Sandbox doesn't accept phone recipients, so you can't run the phone
  signup there. Test the card session steps in Sandbox with
  [`POST /simulations/invite-customer`](/api-reference/simulations/create-test-customer).
* **No VoIP numbers.** Invite the number in E.164 format, such as `+14155550123`. Natural blocks
  VoIP numbers, such as Google Voice, at signup. Creating the invitation doesn't check this.
* **Card only.** A phone-only user can't accept an invitation that asks for more than card
  access. If your agent later needs to move money, the user needs a full account.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.