" }
}
}
}
```
## User-scoped vs agent-scoped OAuth
Natural's consent screen determines who the connection acts as:
* **As an agent (agent-scoped)** — The default: pick one of your existing agents or create a new one during approval. Every tool call then acts as that agent with a verified binding, and audit records both the agent and the authorizing user. Agent-scoped connections can't call `create_agent` or manage keys.
* **As me (user-scoped)** — Tool calls are your own user/party actions, with no agent attribution needed. A consent screen with no agent selection grants user-scoped access.
To switch modes, disconnect Natural in the host and reconnect with the other selection.
## What you can do
The connector exposes 23 tools, each shaped around an intent. Each one handles the orchestration for you (finding the right wallet, detecting the payer type, auto-selecting a single account), so the agent just says what it wants instead of chaining calls.
| Tool | Purpose |
| -------------------------- | ---------------------------------------------------------------------------------- |
| `get_transaction_status` | Look up a single payment or transfer by id (`pay_*` or `trf_*`) |
| `wait_for_transaction` | Block until a payment/transfer reaches a terminal status (event-driven; max 60s) |
| `get_payment_request` | Look up a payment request by id (`prq_*`) |
| `list_transactions` | Paginated transaction history |
| `get_account_balance` | Wallet balance (available plus pending claims) |
| `list_wallets` | Wallet IDs, names, status, default flags, and balances for user/party callers |
| `get_identity` | Caller party, acting agent when present, handles, and credential permissions |
| `get_party_limits` | Per-transaction, daily, and monthly spend limits for the party (read-only) |
| `list_external_accounts` | Linked external accounts and provider connection status |
| `get_external_account` | One linked external account by id (`eac_*`) |
| `create_payment` | Send a payment. Recipient is an email / phone / `@handle` / `pty_*` / `agt_*` |
| `cancel_payment` | Cancel a pending-claim outbound payment by id (`pay_*`) before it is claimed |
| `request_payment` | Request a payment. Payer is an email / phone / `@handle` / `pty_*` / `agt_*` |
| `fulfill_payment_request` | Pay a request after confirming its current amount and currency |
| `decline_payment_request` | Decline an incoming request (`prq_*`) without paying it |
| `deposit_funds` | ACH pull from a linked account; falls back to push-to-wallet instructions |
| `withdraw_funds` | ACH push to a linked account; auto-selects when exactly one is active |
| `transfer_between_wallets` | Move funds between two of your own wallets (`wal_*` to `wal_*`); returns `trf_*` |
| `list_agents` | Your agents |
| `list_customers` | Your customer relationships (`status` is `active`, `pending`, `revoked`, or `all`) |
| `create_agent` | Mint a new programmatic actor (your own party only) |
| `invite_customer` | Send a customer invitation by email |
| `get_funding_options` | Linked bank accounts + ACH push-to-wallet instructions in one view |
### Amounts and currencies
MCP payment tools use a decimal amount and a three-letter currency code:
```json theme={null}
{
"amount": "10.50",
"currency": "USD"
}
```
Natural preserves the amount you give it: `$5` becomes `"5.00"` and `$5.3` becomes `"5.30"` without changing the value. If an amount cannot be represented exactly (for example, a USD amount with fractions of a cent), the agent should ask which exact amount to send instead of rounding it. The payment tool accepts only exact decimal amounts without currency symbols or commas, and `currency` is always required.
In manual approval mode, your host shows the amount, currency, and destination before the payment runs. When paying a payment request, Natural checks its current amount and currency again and stops if either changed.
This format applies to MCP. Natural's REST API and SDKs use integer minor units. See [Data
formats](/api-reference/formats).
## Attribution for production agents
With an **agent-scoped OAuth grant or an agent key**, agent identity is carried by the credential. For money-moving tools, pass `instanceId` every run so each is auditable.
With a **user-scoped grant or a party API key**, tool calls are user/party actions and need no attribution fields.
Tools do not take an `agentId` argument: agent identity comes only from an agent-scoped OAuth grant or an agent key.
## Test in the sandbox
The [sandbox](/api-reference/sandbox/overview) runs its own MCP server at **`https://mcp.sandbox.natural.com`**. Connect it like the production server; it adds sandbox-only tools (`simulate_customer_deposit`, `simulate_customer_invitation_accept`, and friends) so an agent can drive both sides of a flow. See [Sandbox from MCP, CLI, and SDKs](/api-reference/sandbox/surfaces).
## Docs MCP server
This documentation runs its own MCP server at **`https://docs.natural.com/mcp`**, separate from the payments server at `mcp.natural.com`. It requires no Natural account or credentials, so an agent can use it before signup or OAuth. Its tools search these docs, read full pages, and pull the exact request shape of any endpoint from the [OpenAPI spec](/api-reference/openapi.json).
```json theme={null}
{
"mcpServers": {
"natural-docs": {
"url": "https://docs.natural.com/mcp"
}
}
}
```
Connect it alongside the payments server while integrating; it is read-only and moves no money.
## Troubleshooting
* **Missing tools after connecting** — Reload the host's MCP tools or restart the host window after OAuth completes.
* **Auth fails after a previous success** — Disconnect Natural in the host, reconnect, and approve the OAuth screen again.
* **Tool reports missing account setup** — Finish KYC/KYB, wallet, or linked-bank setup in the Natural dashboard, then reconnect.
For support, include the host name, server URL used, approximate timestamp, your Natural email, any request ID, any visible identifier (`txn_*`, `prq_*`, `pay_*`), and the exact error text.
## Related
* [Authentication](/api-reference/authentication) — API keys and scopes
* [Agents](/guides/concepts/agents) — The autonomous-actor model behind the connector
* [SDKs](/guides/platform/sdks) — Python and TypeScript client libraries
* [CLI](/guides/platform/cli) — For terminal and CI use
# Reliability
Source: https://docs.natural.com/guides/platform/reliability
How Natural stays available and behaves predictably under failure
You rely on Natural to run agents, hold funds in wallets, and move money, so the platform is built to stay available and to behave predictably when something fails. This page covers how we run the service and how the API responds under failure.
## Infrastructure
Natural runs on AWS across multiple availability zones and is served through a global CDN. If an instance or an entire availability zone fails, traffic shifts to healthy capacity automatically.
## Data
Your data lives in Amazon Aurora PostgreSQL, running with a primary and a replica across availability zones so the database survives the loss of any single zone. It is encrypted at rest with AWS KMS and backed up automatically. For how data is encrypted and protected, see [Security](/guides/overview/security).
## Behavior under failure
The API is built so that a failure or a retry never leaves your data in the wrong state, whether you are creating an agent, funding a wallet, or sending a payment.
### Idempotency
Any operation whose accidental repetition would matter, like funding a wallet or sending a payment, takes an `Idempotency-Key`. Retrying with the same key never runs the operation twice, and the recorded outcome, success or failure, replays for 48 hours. See [Idempotency](/api-reference/idempotency).
### Retries
Transient failures are safe to retry with exponential backoff. A `429` response carries a `Retry-After` header, and `5xx` responses and network timeouts can be retried under the same idempotency key. See [Rate limits](/api-reference/rate-limits).
### Webhooks
Events are delivered at least once from a durable queue. Each event is retried up to seven times over roughly a day with jitter, times out after 30 seconds per attempt, and carries a stable `webhook-id` so you can deduplicate. An endpoint that fails five events in a row is disabled until you re-enable it. See [Webhooks](/guides/webhooks-integration).
### Compatibility
The Natural API is additive. We add fields and endpoints, but we do not remove or repurpose the ones you already depend on. See [Backwards compatibility](/api-reference/backwards-compatibility).
## Status
Live service status is published at [status.natural.com](https://status.natural.com), covering the API, Dashboard, MCP, and Webhooks. Subscribe there to be notified of incidents.
## Related
* [Idempotency](/api-reference/idempotency) - Safe retries for mutations
* [Webhooks](/guides/webhooks-integration) - Event delivery and verification
* [Security](/guides/overview/security) - How we protect data and control access
# SDKs
Source: https://docs.natural.com/guides/platform/sdks
Client libraries for building agents with Natural
Natural has official SDKs for building agents, in Python and TypeScript.
## Available tools
`pip install naturalpay` - Build agents in Python
`npm install @naturalpay/sdk` - Build agents in TypeScript/JavaScript
## Installation
```bash Python theme={null}
pip install naturalpay
# or
uv add naturalpay
```
```bash TypeScript theme={null}
npm install @naturalpay/sdk
# or
yarn add @naturalpay/sdk
```
## Quick start
```python Python theme={null}
from naturalpay import Natural
# Agent key from NATURAL_API_KEY; instance_id identifies this run.
client = Natural(instance_id="invoice-run-1234")
# Create a payment on behalf of a customer
payment = client.payments.create(
amount=10000, # cents - $100.00
currency="USD",
counterparty={"type": "email", "value": "contractor@example.com"},
description="Invoice #1234",
customer_party_id="pty_019cd34e27c179bfbbe6870486b11b67",
idempotency_key="pay-invoice-1234",
)
print(payment.data.id)
print(payment.data.attributes.status)
```
```typescript TypeScript theme={null}
import Natural from "@naturalpay/sdk";
// One client per run: instanceId names the run, and the SDK sends it
// as X-Instance-ID on every call this client makes.
const client = new Natural({ instanceId: "invoice-run-1234" }); // agent key from NATURAL_API_KEY
// Create a payment on behalf of a customer
const payment = await client.payments.create({
amount: 10000, // cents - $100.00
currency: "USD",
counterparty: { type: "email", value: "contractor@example.com" },
description: "Invoice #1234",
customerPartyId: "pty_019cd34e27c179bfbbe6870486b11b67",
idempotencyKey: "pay-invoice-1234",
});
console.log(payment.data.id);
console.log(payment.data.attributes.status);
```
## Agent authentication
Both SDKs accept either credential type in `NATURAL_API_KEY` (see [Authentication](/api-reference/authentication)):
* **Agent key** (`ak_ntl_…`) — Bound to one agent. Requests resolve as that agent automatically: do **not** pass an agent ID (a conflicting one is rejected). An instance ID is **required** for money movement (`payments.create`, transfers, payment-request fulfillment) so each agent run is auditable. In Python, pass `instance_id` to the client constructor and build a client per run. In TypeScript, set it on the constructor or per call.
* **API key** (`sk_ntl_…`) — Party-scoped. Calls act as your party and cannot act as an agent (see [Authentication](/api-reference/authentication#agent-keys)).
### With an agent key
```python Python theme={null}
# NATURAL_API_KEY=ak_ntl_prod_...
# One client per run: instance_id names the run, and the SDK sends it
# as X-Instance-ID on every call this client makes.
client = Natural(instance_id="vendor-payouts-q1")
payment = client.payments.create(
counterparty={"type": "email", "value": "vendor@example.com"},
amount=50000, # cents ($500.00)
description="Vendor payment",
customer_party_id="pty_019cd34e27c27605a92edc2c7d1a5b34",
idempotency_key="vendor_payment_001",
)
```
```typescript TypeScript theme={null}
// NATURAL_API_KEY=ak_ntl_prod_...
// One client per run: instanceId is required for money movement with an agent key.
const client = new Natural({ instanceId: "vendor-payouts-q1" });
const payment = await client.payments.create({
counterparty: { type: "email", value: "vendor@example.com" },
amount: 50000, // cents ($500.00)
description: "Vendor payment",
customerPartyId: "pty_019cd34e27c27605a92edc2c7d1a5b34",
idempotencyKey: "vendor_payment_001",
});
```
## Available resources
Both SDKs provide these resources. Python names them in snake\_case (`payment_requests`), TypeScript in camelCase (`paymentRequests`):
| Resource | Description |
| ------------------- | ------------------------------------------------------- |
| `payments` | Create, list, and cancel payments |
| `payment_requests` | Create, fulfill, and decline payment requests |
| `wallets` | Balances, wallet management, and agent attachment |
| `transfers` | Deposits, withdrawals, and internal transfers |
| `transactions` | List transaction history |
| `external_accounts` | Linked bank accounts |
| `agents` | Create and manage agents |
| `customers` | Customer relationships and invitations |
| `invitations` | Agent delegation invitations |
| `approvals` | Review and act on approval requests |
| `parties` | Party profile, limits, handle, and members |
| `identity` | Resolve who a credential acts as |
| `api_keys` | Create and revoke API keys |
| `agent_keys` | Create, rotate, and revoke agent keys |
| `webhooks` | Webhook subscriptions |
| `events` | Published event history |
| `simulations` | Sandbox only: drive the counterparty side of test flows |
## Test in the sandbox
Both SDKs run against the [sandbox](/api-reference/sandbox/overview) unchanged: use a sandbox key and the sandbox base URL. The sandbox-only `simulations` resource drives the counterparty side of every flow.
```typescript TypeScript theme={null}
// NATURAL_API_KEY=sk_ntl_sandbox_...
const client = new Natural({ baseUrl: "https://api.sandbox.natural.com" });
```
```python Python theme={null}
# NATURAL_API_KEY=sk_ntl_sandbox_...
client = Natural(base_url="https://api.sandbox.natural.com")
```
See [Sandbox from MCP, CLI, and SDKs](/api-reference/sandbox/surfaces) for the full simulation surface.
## Related
* [MCP](/guides/platform/mcp) — Connect Claude, Cursor, and other AI hosts to Natural
* [CLI](/guides/platform/cli) — For terminal and CI use
* [Dashboard](/guides/platform/dashboard) — Onboarding and managing your account
* [REST API](/api-reference/about) — Direct HTTP access to the Natural API
# Accept
Source: https://docs.natural.com/guides/products/accept
Accept card payments by giving your agents merchant capabilities, all through API
Turn your agent into a merchant to accept card payments, all through API. Works for businesses of any size, from new companies to large enterprises.
## Turn your agent into a merchant
* **Flexible payment methods**: Accept debit cards, credit cards, bank transfers, and more.
* **Fully programmable**: Accept payments via one-time link or fully programmatically.
* **Total visibility**: Every payment is observable and fully auditable so you have maximum visibility.
# Cards
Source: https://docs.natural.com/guides/products/cards
Issue debit and charge cards for your agents the moment they're connected
Issue debit and charge cards for your agents the moment they’re connected. The access controls, MCCs, and limits you’re already familiar with, but for agents.
## Give your agent a card
* **Programmatic issuing**: Create virtual cards and network tokens with API calls via Natural.
* **Flexible checkout**: Bring your own browser automation or use Natural for direct checkout.
* **PCI compliant**: Let Natural handle all PCI data so that you stay compliant.
# Connect
Source: https://docs.natural.com/guides/products/connect
Build a platform that enables money movement for your customers across all of Natural's products
Build a platform that enables money movement for your customers. Grant access to your agents across your customers and give your customers the full suite of Natural products.
## Create your platform
* **Full platform capabilities**: Your customers get full access to all Natural products like Wallets, Pay, Accept, and more.
* **Fully programmable**: Invite customers and orchestrate money movement all via the API.
* **Create dynamic workflows**: Connect multiple agents at a time, each powering one or more workflows.
# Pay
Source: https://docs.natural.com/guides/products/pay
Pay an agent, email, phone number, and more. Natural powers every type of payments workflow
Pay an agent, email, phone number, and more. Natural powers every type of payments workflow, handling the orchestration, ledgering, routing, compliance, risk, and disputes.
## Pay anyone for anything
* **Start building immediately**: Pay an agent, email, or phone number. Natural handles the onboarding and compliance.
* **Safe by design**: Rely on Natural's network to manage risk, flag fraudulent transactions, and handle disputes.
* **Built for scale**: Whether your agent makes one transaction or one million, Natural scales with you.
# Request
Source: https://docs.natural.com/guides/products/request
Request a payment from an agent, email, or phone number with a single API call
Request from an agent, email, phone number, and more. Natural powers every type of payments workflow, handling the orchestration, ledgering, routing, compliance, risk, and disputes.
## Request money from anyone
* **Start building immediately**: Request from an agent, email, or phone number. Natural handles the rest.
* **Safe by design**: Rely on Natural's network to manage risk, flag fraudulent transactions, and handle disputes.
* **Built for scale**: Whether your agent makes one transaction or one million, Natural scales with you.
# Transfer
Source: https://docs.natural.com/guides/products/transfer
Transfer money between external accounts with automated treasury management for your agents
Transfer money between internal and external accounts. Give your agents access to automated treasury management and empower your financial stack.
## Agentic financial management
* **Multiple rails**: Natural handles all types of payment rails so you can use what is best for you.
* **Fully programmable**: Any connected agent can send, receive, or request funds with an API call.
* **Total visibility**: Every transfer is observable and fully auditable so you have maximum visibility.
# Vault
Source: https://docs.natural.com/guides/products/vault
Receive expanded FDIC coverage with a special protected wallet for your financial reserves
One-way accounts for agents. Money moves in, never out. Store funds in a Vault to keep them separate from the accounts your agents can access.
## Peace of mind with Vaults
* **Expanded FDIC insurance**1: All Natural accounts receive expanded FDIC coverage.
* **Stay in control**: Agents are only allowed to deposit into vaults, but can’t move money out.
* **Instant transfers**: Move money between your Vault and Wallets instantly for free.
1 Natural is a financial technology company, not an FDIC-insured depository
institution. FDIC deposit insurance covers the failure of an insured depository institution.
Certain conditions must be satisfied for pass-through FDIC insurance to apply. Deposits are
FDIC-insured through Column N.A., Member FDIC, and Column's
Sweep Program Network Banks.
# Voice
Source: https://docs.natural.com/guides/products/voice
Turn a live phone call into a PCI-compliant card charge from a single call transfer
Turn a phone call into a PCI-compliant payment. Use Voice to collect card information and other payments over the phone, all from a single call transfer.
## Technology for voice agents
* **PCI compliant**: Transfer your call to Natural to keep your system completely out of PCI scope.
* **Capture spoken card details**: Natural can handle DTMF and spoken card details.
* **Tokenized card credentials**: Natural tokenizes the card information and stores that payment credentials for you.
# Wallet
Source: https://docs.natural.com/guides/products/wallet
Store funds in FDIC-insured accounts to hold, send, and receive funds, all from an API
Store funds in FDIC-insured1 wallets for your agent to use. Create a single wallet or spin up multiple to manage finances. All from one unified API.
## Accounts built for agents
* **Multiple wallets**: Use one wallet for all your agents, or one for each. You decide.
* **Expanded FDIC insurance**1: All Natural accounts receive expanded FDIC coverage.
* **Fully programmable**: Create new wallets on top of Natural entirely programmatically.
1 Natural is a financial technology company, not an FDIC-insured depository
institution. FDIC deposit insurance covers the failure of an insured depository institution.
Certain conditions must be satisfied for pass-through FDIC insurance to apply. Deposits in Wallet
accounts are FDIC-insured through Column N.A., Member FDIC, and Column's
Sweep Program Network Banks.
# Deposit and withdraw
Source: https://docs.natural.com/guides/transfers/deposit-and-withdraw
Transfer from an external account.
Move money between a linked bank account and your Natural wallet. A deposit pulls funds in, a withdrawal pushes funds out. Both settle asynchronously.
Link a bank account in the dashboard first. Natural connects it through Plaid and returns an
`eac_` id you pass on every deposit and withdrawal.
## Deposit into a wallet
Pull money from the bank into a wallet with [`POST /transfers/deposit`](/api-reference/transfers/initiate-deposit). Funds land in your default wallet unless you name another.
```python Python theme={null}
import uuid
from naturalpay import Natural
client = Natural()
deposit = client.transfers.initiate_deposit(
amount=50_000,
currency="USD",
external_account_id="eac_550e8400e29b41d4a716446655440000",
description="Wallet top-up",
idempotency_key=str(uuid.uuid4()),
)
print(deposit.data.id)
```
```typescript TypeScript theme={null}
import Natural from "@naturalpay/sdk";
const client = new Natural();
const deposit = await client.transfers.initiateDeposit({
amount: 50_000,
currency: "USD",
externalAccountId: "eac_550e8400e29b41d4a716446655440000",
description: "Wallet top-up",
idempotencyKey: crypto.randomUUID(),
});
console.log(deposit.data.id);
```
```bash CLI theme={null}
natural transfers initiateDeposit \
--amount 50000 \
--currency USD \
--external-account-id eac_550e8400e29b41d4a716446655440000 \
--description "Wallet top-up" \
--idempotency-key "$(uuidgen)"
```
```text MCP theme={null}
Deposit $500 into my wallet from my linked bank account.
```
```bash cURL theme={null}
curl -X POST https://api.natural.com/transfers/deposit \
-H "Authorization: Bearer $NATURAL_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"data": {
"attributes": {
"amount": 50000,
"currency": "USD",
"externalAccountId": "eac_550e8400e29b41d4a716446655440000",
"description": "Wallet top-up"
}
}
}'
```
## Withdraw to a bank account
Push money from a wallet to the bank with [`POST /transfers/withdraw`](/api-reference/transfers/initiate-withdrawal). Natural pulls from your default wallet unless you name another, and the wallet needs enough available balance to cover it.
```python Python theme={null}
withdrawal = client.transfers.initiate_withdrawal(
amount=12_500,
currency="USD",
external_account_id="eac_550e8400e29b41d4a716446655440000",
description="Payout transfer",
idempotency_key=str(uuid.uuid4()),
)
print(withdrawal.data.id)
```
```typescript TypeScript theme={null}
const withdrawal = await client.transfers.initiateWithdrawal({
amount: 12_500,
currency: "USD",
externalAccountId: "eac_550e8400e29b41d4a716446655440000",
description: "Payout transfer",
idempotencyKey: crypto.randomUUID(),
});
console.log(withdrawal.data.id);
```
```bash CLI theme={null}
natural transfers initiateWithdrawal \
--amount 12500 \
--currency USD \
--external-account-id eac_550e8400e29b41d4a716446655440000 \
--description "Payout transfer" \
--idempotency-key "$(uuidgen)"
```
```text MCP theme={null}
Withdraw $125 from my wallet to my linked bank account.
```
```bash cURL theme={null}
curl -X POST https://api.natural.com/transfers/withdraw \
-H "Authorization: Bearer $NATURAL_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"data": {
"attributes": {
"amount": 12500,
"currency": "USD",
"externalAccountId": "eac_550e8400e29b41d4a716446655440000",
"description": "Payout transfer"
}
}
}'
```
## Confirm the balance
Deposits and withdrawals settle over a few business days, so the balance change is not immediate. Read the wallet to confirm a deposit landed before you spend against it, or that a withdrawal left. See [Wallets](/guides/wallets/wallets) for how `balance.available` differs from `balance.total`.
# Transfer between wallets
Source: https://docs.natural.com/guides/transfers/transfer-between-wallets
Move money instantly between two wallets
## Move funds
A transfer moves money between two wallets in the same party, landing instantly. Create one with [`POST /transfers/internal`](/api-reference/transfers/initiate-internal-transfer).
```python Python theme={null}
import uuid
from naturalpay import Natural
client = Natural()
transfer = client.transfers.initiate_internal(
amount=5_000,
source_wallet_id="wal_550e8400e29b41d4a716446655440000",
dest_wallet_id="wal_7c9e6679e29b41d4a716446655440002",
description="Sweep to Vault",
idempotency_key=str(uuid.uuid4()),
)
print(transfer.data.id)
```
```typescript TypeScript theme={null}
import Natural from "@naturalpay/sdk";
const client = new Natural();
const transfer = await client.transfers.initiateInternal({
amount: 5_000,
sourceWalletId: "wal_550e8400e29b41d4a716446655440000",
destWalletId: "wal_7c9e6679e29b41d4a716446655440002",
description: "Sweep to Vault",
idempotencyKey: crypto.randomUUID(),
});
console.log(transfer.data.id);
```
```bash CLI theme={null}
natural transfers initiateInternal \
--amount 5000 \
--source-wallet-id wal_550e8400e29b41d4a716446655440000 \
--dest-wallet-id wal_7c9e6679e29b41d4a716446655440002 \
--description "Sweep to Vault" \
--idempotency-key "$(uuidgen)"
```
```text MCP theme={null}
Move $50 from my operating wallet to my Vault.
```
```bash cURL theme={null}
curl -X POST https://api.natural.com/transfers/internal \
-H "Authorization: Bearer $NATURAL_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"data": {
"attributes": {
"amount": 5000,
"sourceWalletId": "wal_550e8400e29b41d4a716446655440000",
"destWalletId": "wal_7c9e6679e29b41d4a716446655440002",
"description": "Sweep to Vault"
}
}
}'
```
# Vault
Source: https://docs.natural.com/guides/wallets/vault
A reserve wallet agents can fund but never spend from
The Vault is a reserve wallet that no agent can spend from. It keeps money separate from your day-to-day agent activity. Anyone can move money in, including agents, but no agent can take money out.
## What the Vault is
Every wallet has a `walletType` of `standard` or `vault`. A standard wallet is the everyday, spendable one. The Vault is the locked-down reserve.
List your wallets with [`GET /wallets`](/api-reference/wallets/list-wallets) to see the field. The Vault sits alongside your standard wallets, set apart only by its `walletType`.
```python Python theme={null}
from naturalpay import Natural
client = Natural()
wallets = client.wallets.list()
for wallet in wallets.data:
print(wallet.id, wallet.attributes.display_name, wallet.attributes.wallet_type)
```
```typescript TypeScript theme={null}
import Natural from "@naturalpay/sdk";
const client = new Natural();
const wallets = await client.wallets.list();
for (const wallet of wallets.data) {
console.log(wallet.id, wallet.attributes.displayName, wallet.attributes.walletType);
}
```
```bash CLI theme={null}
natural wallets list
```
```text MCP theme={null}
List my Natural wallets and show each one's type and balance.
```
```bash cURL theme={null}
curl https://api.natural.com/wallets \
-H "Authorization: Bearer $NATURAL_API_KEY"
```
## How the Vault differs
The Vault behaves differently from a standard wallet in three ways.
**1. You cannot create one through the API.** The Vault is provisioned once after onboarding.
**2. Agents cannot be attached to Vault or move money out of it.** Agents can still fund the Vault by transferring in from a standard wallet.
**3. It cannot be your default wallet.** Keep a standard wallet as your default so calls that omit `walletId` resolve somewhere spendable.
# Wallets
Source: https://docs.natural.com/guides/wallets/wallets
Create and manage your wallets
Wallets holds your money on Natural. You can open multiple to keep funds separate: payroll separate from operating cash, or a dedicated pool per agent.
## Create a wallet
Create a new wallet with [`POST /wallets`](/api-reference/wallets/create-wallet).
```python Python theme={null}
import uuid
from naturalpay import Natural
client = Natural()
wallet = client.wallets.create(
idempotency_key=str(uuid.uuid4()),
display_name="Payroll",
description="Dedicated wallet for payroll runs",
)
print(wallet.data.id)
```
```typescript TypeScript theme={null}
import Natural from "@naturalpay/sdk";
const client = new Natural();
const wallet = await client.wallets.create({
idempotencyKey: crypto.randomUUID(),
displayName: "Payroll",
description: "Dedicated wallet for payroll runs",
});
console.log(wallet.data.id);
```
```bash CLI theme={null}
natural wallets create \
--idempotency-key "$(uuidgen)" \
--display-name "Payroll" \
--description "Dedicated wallet for payroll runs"
```
```bash cURL theme={null}
curl -X POST https://api.natural.com/wallets \
-H "Authorization: Bearer $NATURAL_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"data": {
"attributes": {
"displayName": "Payroll",
"description": "Dedicated wallet for payroll runs"
}
}
}'
```
The API only creates `standard` wallets. The **Vault** is set up automatically, never through the
API. See [Vault](/guides/wallets/vault).
A new wallet starts empty. Fund it by [depositing from a linked bank account](/guides/transfers/deposit-and-withdraw), or [transfer money in from another of your wallets](/guides/transfers/transfer-between-wallets).
## Check a balance
List all walletes in one call to [`GET /wallets`](/api-reference/wallets/list-wallets) and get details with [`GET /wallets/{walletId}`](/api-reference/wallets/get-wallet).
```python Python theme={null}
wallets = client.wallets.list()
for wallet in wallets.data:
balance = wallet.attributes.balance
available = balance.available if balance else 0
print(wallet.id, wallet.attributes.display_name, available)
```
```typescript TypeScript theme={null}
const wallets = await client.wallets.list();
for (const wallet of wallets.data) {
console.log(wallet.id, wallet.attributes.displayName, wallet.attributes.balance?.available ?? 0);
}
```
```bash CLI theme={null}
natural wallets list
```
```text MCP theme={null}
What is my wallet balance?
```
```bash cURL theme={null}
curl https://api.natural.com/wallets \
-H "Authorization: Bearer $NATURAL_API_KEY"
```
Each wallet carries two figures: available and total. available is what you can spend now, with total including pending transfers and holds. Generally you should always opt for using available balance.
To read one wallet, pass its id to [`GET /wallets/{walletId}`](/api-reference/wallets/get-wallet):
```python Python theme={null}
wallet = client.wallets.get("wal_550e8400e29b41d4a716446655440000")
balance = wallet.data.attributes.balance
print(balance.available if balance else 0)
```
```typescript TypeScript theme={null}
const wallet = await client.wallets.get({
walletId: "wal_550e8400e29b41d4a716446655440000",
});
console.log(wallet.data.attributes.balance?.available ?? 0);
```
```bash CLI theme={null}
natural wallets get --wallet-id wal_550e8400e29b41d4a716446655440000
```
```bash cURL theme={null}
curl https://api.natural.com/wallets/wal_550e8400e29b41d4a716446655440000 \
-H "Authorization: Bearer $NATURAL_API_KEY"
```
## Rename a wallet
Rename a wallet or change its description with [`PATCH /wallets/{walletId}`](/api-reference/wallets/update-wallet).
```python Python theme={null}
wallet = client.wallets.update(
"wal_550e8400e29b41d4a716446655440000",
idempotency_key=str(uuid.uuid4()),
display_name="Operating (US)",
description="Primary USD operating wallet",
)
```
```typescript TypeScript theme={null}
const wallet = await client.wallets.update({
walletId: "wal_550e8400e29b41d4a716446655440000",
idempotencyKey: crypto.randomUUID(),
displayName: "Operating (US)",
description: "Primary USD operating wallet",
});
```
```bash CLI theme={null}
natural wallets update \
--wallet-id wal_550e8400e29b41d4a716446655440000 \
--idempotency-key "$(uuidgen)" \
--display-name "Operating (US)" \
--description "Primary USD operating wallet"
```
```bash cURL theme={null}
curl -X PATCH https://api.natural.com/wallets/wal_550e8400e29b41d4a716446655440000 \
-H "Authorization: Bearer $NATURAL_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "data": { "attributes": { "displayName": "Operating (US)", "description": "Primary USD operating wallet" } } }'
```
## Set your default
Your default wallet is where Natural puts money when a payment, deposit, or withdrawal omits `walletId`, and where payments to your email, phone, or handle land. Set it with [`POST /wallets/{walletId}/default`](/api-reference/wallets/set-default-wallet).
The default is a party-level setting: exactly one wallet is your party's default, and setting a new one clears the old. Each agent also has its own default, set separately. See [Wallet access](/guides/controls/wallet-access).
```python Python theme={null}
client.wallets.set_default(
"wal_550e8400e29b41d4a716446655440000",
idempotency_key=str(uuid.uuid4()),
)
```
```typescript TypeScript theme={null}
await client.wallets.setDefault({
walletId: "wal_550e8400e29b41d4a716446655440000",
idempotencyKey: crypto.randomUUID(),
});
```
```bash CLI theme={null}
natural wallets setDefault \
--wallet-id wal_550e8400e29b41d4a716446655440000 \
--idempotency-key "$(uuidgen)"
```
```bash cURL theme={null}
curl -X POST https://api.natural.com/wallets/wal_550e8400e29b41d4a716446655440000/default \
-H "Authorization: Bearer $NATURAL_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"
```
The Vault cannot be your default. Keep a standard wallet as your default so calls that leave out
`walletId` always resolve somewhere spendable.
## Freeze a wallet
Freezing with [`POST /wallets/{walletId}/freeze`](/api-reference/wallets/freeze-wallet) stops money moving in or out while leaving the balance intact. Unfreeze with [`POST /wallets/{walletId}/unfreeze`](/api-reference/wallets/unfreeze-wallet) to return the wallet to `active`.
```python Python theme={null}
client.wallets.freeze("wal_550e8400e29b41d4a716446655440000")
client.wallets.unfreeze("wal_550e8400e29b41d4a716446655440000")
```
```typescript TypeScript theme={null}
await client.wallets.freeze({ walletId: "wal_550e8400e29b41d4a716446655440000" });
await client.wallets.unfreeze({ walletId: "wal_550e8400e29b41d4a716446655440000" });
```
```bash CLI theme={null}
natural wallets freeze --wallet-id wal_550e8400e29b41d4a716446655440000
natural wallets unfreeze --wallet-id wal_550e8400e29b41d4a716446655440000
```
```bash cURL theme={null}
curl -X POST https://api.natural.com/wallets/wal_550e8400e29b41d4a716446655440000/freeze \
-H "Authorization: Bearer $NATURAL_API_KEY"
curl -X POST https://api.natural.com/wallets/wal_550e8400e29b41d4a716446655440000/unfreeze \
-H "Authorization: Bearer $NATURAL_API_KEY"
```
You cannot freeze your party's default wallet. Make another wallet the default first.