> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.thepennyinc.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.thepennyinc.com/_mcp/server.

# Linking an Account

A **linked account** is an external bank account you register with Penny as a source of incoming funds. When Penny receives funds from a registered linked account, it routes them to your Capital Account, where they appear as an `inbound` transaction with a `bank` channel. See [Transactions](/banking/transactions#linked-accounts-and-funding-capital-accounts) for how that transaction looks.

> **Info**
>
> Details of where to send funds are coming soon.

This recipe walks through creating a linked account, reading it back, listing your linked accounts, and deleting one. All requests go to Penny Banking (`https://sandbox.api.thepennyinc.com` in sandbox).

## 1. Create the linked account

`POST /accounts/linked/` registers an external bank account as a source of incoming funds. `country` and `currency` are required; `US` and `USD` are the supported values.

`account_details` is selected by its `type`: pass a `us_account` object (`account_number`, `routing_number`, `us_account_type`) or an `iban` object (`iban`), depending on how the external account is identified.

**`cURL`**

```bash title="cURL"
curl -X POST https://sandbox.api.thepennyinc.com/accounts/linked/ \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "country": "US",
    "currency": "USD",
    "account_details": {
      "type": "us_account",
      "account_number": "000123456789",
      "routing_number": "021000021",
      "us_account_type": "checking"
    }
  }'
```

**`Python`**

```python title="Python"
import requests

BANKING = "https://sandbox.api.thepennyinc.com"
headers = {"Authorization": f"Bearer {access_token}"}

linked_account = requests.post(
    f"{BANKING}/accounts/linked/",
    headers=headers,
    json={
        "country": "US",
        "currency": "USD",
        "account_details": {
            "type": "us_account",
            "account_number": "000123456789",
            "routing_number": "021000021",
            "us_account_type": "checking",
        },
    },
).json()
account_id = linked_account["account_id"]
```

**`JavaScript`**

```javascript title="JavaScript"
const BANKING = "https://sandbox.api.thepennyinc.com";
const headers = {
  Authorization: `Bearer ${accessToken}`,
  "Content-Type": "application/json",
};

const linkedAccount = await fetch(`${BANKING}/accounts/linked/`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    country: "US",
    currency: "USD",
    account_details: {
      type: "us_account",
      account_number: "000123456789",
      routing_number: "021000021",
      us_account_type: "checking",
    },
  }),
}).then((res) => res.json());
const accountId = linkedAccount.account_id;
```

The response is the new linked account, with `account_number` and `routing_number` (or `iban`) masked. In responses, the US account type is reported as `account_details.account_type`:

**`201 Created`**

```json title="201 Created"
{
  "account_id": "account_01937c9e-5b2f-7c41-9a70-5b2f7c419a70",
  "type": "linked",
  "version": 1,
  "version_time": "2026-01-15T18:32:00Z",
  "status": "pending_approval",
  "currency": "USD",
  "country": "US",
  "account_details": {
    "type": "us_account",
    "account_number": "**********",
    "routing_number": "**********",
    "account_type": "checking"
  }
}
```

`alias` and `description` are `null` on a new linked account, so they're omitted. A new linked account may start in `pending_approval` while Penny reviews it. Penny routes funds from a linked account to your Capital Account once its `status` is `approved`.

## 2. Get a linked account

**`cURL`**

```bash title="cURL"
curl https://sandbox.api.thepennyinc.com/accounts/linked/$ACCOUNT_ID \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

**`Python`**

```python title="Python"
requests.get(f"{BANKING}/accounts/linked/{account_id}", headers=headers).json()
```

**`JavaScript`**

```javascript title="JavaScript"
await fetch(`${BANKING}/accounts/linked/${accountId}`, { headers }).then((res) =>
  res.json()
);
```

Pass `?version=` to look up a specific past version of the record. It defaults to `0`, which selects the latest version.

The account/routing number or IBAN comes back masked by default here too. Pass `?reveal_sensitive=true` if you need the real value:

**`cURL`**

```bash title="cURL"
curl "https://sandbox.api.thepennyinc.com/accounts/linked/$ACCOUNT_ID?reveal_sensitive=true" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

## 3. List linked accounts

**`cURL`**

```bash title="cURL"
curl "https://sandbox.api.thepennyinc.com/accounts/linked/?status=approved" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

**`Python`**

```python title="Python"
requests.get(
    f"{BANKING}/accounts/linked/",
    headers=headers,
    params={"status": "approved"},
).json()
```

**`JavaScript`**

```javascript title="JavaScript"
await fetch(`${BANKING}/accounts/linked/?status=approved`, { headers }).then((res) =>
  res.json()
);
```

`status` is optional and filters to one of `created`, `pending_approval`, `approved`, `rejected`, `suspended`, or `deleted`. Omit it to get every linked account regardless of status. Results are paginated like any other list endpoint. Account and routing numbers and IBANs are always masked in list results, and there's no `reveal_sensitive` option here; fetch the individual account (step 2) if you need the real value.

## 4. Delete a linked account

Deleting a linked account marks it `deleted` rather than removing the record. Penny stops accepting it as a source of funds, and its history is preserved. The response is the linked account with `status: "deleted"`.

**`cURL`**

```bash title="cURL"
curl -X DELETE https://sandbox.api.thepennyinc.com/accounts/linked/$ACCOUNT_ID \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

**`Python`**

```python title="Python"
requests.delete(f"{BANKING}/accounts/linked/{account_id}", headers=headers).json()
```

**`JavaScript`**

```javascript title="JavaScript"
await fetch(`${BANKING}/accounts/linked/${accountId}`, {
  method: "DELETE",
  headers,
}).then((res) => res.json());
```

Deleting an already-deleted linked account is rejected. Check the `status` first if you're not sure.

## Staying in sync

Subscribe to `linked_account.created` and `linked_account.updated` (see the [Event Catalog](/platform/webhooks-event-catalog)) instead of polling. `linked_account.updated` fires whenever a linked account's status or details change, including approval. See [Subscribing to Webhooks](/platform/subscribing-to-webhooks) for how to set up a subscription.

## Next steps

* [Accounts](/banking/accounts): how Capital Accounts hold balances once money is inside Penny
* [Reading Transactions & Ledger Entries](/banking/reading-transactions): find the transactions for funds received from a linked account
* [Subscribing to Webhooks](/platform/subscribing-to-webhooks): get notified when a linked account is approved