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

# Connect — one platform, many tenants

> Built for accounting apps, ERPs, and platforms that manage invoicing for many businesses under

Built for accounting apps, ERPs, and platforms that manage invoicing for **many businesses** under
a single integration. Modeled on Stripe Connect: you authenticate with **your own platform API key**
and name the tenant to act on with an **`Invoice-Account`** header — no per-tenant keys to store.

## Model

```
platform organization            (your account, holds your sk_test_/sk_live_ keys)
  ├─ connected account org_A      (a client business — its own fiscal_profiles, invoices, downloads…)
  ├─ connected account org_B
  └─ connected account org_C
```

* A **platform** is any organization. A **connected account** is an organization owned by it
  (`parent`). Each connected account is fully isolated: its invoices, fiscal profiles, downloads,
  events, and webhooks are scoped to it — the platform (and sibling accounts) can't read them
  except by explicitly acting as that account.
* One level only: a connected account cannot own connected accounts.
* Connected accounts have **no API keys**. You always authenticate with the platform key.

## 1. Create connected accounts

Use your platform key, no header:

```bash theme={null}
curl -X POST https://api.example.com/v1/accounts \
  -H "authorization: Bearer $PLATFORM_KEY" \
  -H 'content-type: application/json' \
  -d '{ "name": "Tortillería López SA de CV" }'
# → { "object": "account", "id": "org_...", "name": "...", "parent": "org_platform", ... }
```

`GET /v1/accounts` lists them (cursor-paginated); `GET /v1/accounts/:id` retrieves one.

## 2. Act on behalf of a connected account

Send your platform key **plus** the `Invoice-Account` header with the connected account id. Every
endpoint then reads/writes that account's data:

```bash theme={null}
# Register the client's CSD under their account
curl -X POST https://api.example.com/v1/fiscal_profiles \
  -H "authorization: Bearer $PLATFORM_KEY" \
  -H "Invoice-Account: org_client123" \
  -F "legal_name=TORTILLERIA LOPEZ" -F "tax_regime=601" -F "zip=26015" \
  -F "csd_password=…" -F "csd_cer=@csd.cer" -F "csd_key=@csd.key"

# Stamp an invoice for that client
curl -X POST https://api.example.com/v1/invoices \
  -H "authorization: Bearer $PLATFORM_KEY" \
  -H "Invoice-Account: org_client123" \
  -H 'content-type: application/json' \
  -d '{ "fiscal_profile_id": "fp_...", "payment_form": "03", ... }'
```

Notes:

* Prefer a query param? `?account=org_client123` works too; the header wins if both are sent.
* Test vs live is still decided by the key (`sk_test_` → sandbox, `sk_live_` → live). A platform
  test key acting on a connected account operates on that account's **test** data.
* Naming your own platform org (or omitting the header) acts as the platform itself.
* Acting on an account you don't own returns **403 `connect.account_not_authorized`**.

## 3. Manage a connected account

Rename, attach `metadata`, suspend, or delete an account with your platform key (no
`Invoice-Account` header — you are managing the account, not acting as it):

```bash theme={null}
# Rename + tag
curl -X PATCH https://api.example.com/v1/accounts/org_client123 \
  -H "authorization: Bearer $PLATFORM_KEY" -H 'content-type: application/json' \
  -d '{ "name": "Tortillería López (Norte)", "metadata": { "tier": "pro" } }'

# Suspend: any later attempt to act as this account is refused
curl -X PATCH https://api.example.com/v1/accounts/org_client123 \
  -H "authorization: Bearer $PLATFORM_KEY" -H 'content-type: application/json' \
  -d '{ "disabled": true }'
# Acting as it now returns 403 connect.account_disabled until you re-enable:
curl -X PATCH https://api.example.com/v1/accounts/org_client123 \
  -H "authorization: Bearer $PLATFORM_KEY" -H 'content-type: application/json' \
  -d '{ "disabled": false }'

# Delete
curl -X DELETE https://api.example.com/v1/accounts/org_client123 \
  -H "authorization: Bearer $PLATFORM_KEY"
# → { "object": "account", "id": "org_client123", "deleted": true }
```

`metadata` is string→string, merged on PATCH (send a key with an empty-string value to delete it).

## 4. Connect webhooks — every client's events on one endpoint

Instead of registering a webhook per client, register **one** endpoint on the platform with
`connect: true`. It receives events from **all** your connected accounts, and each delivery's
`account` field tells you which one:

```bash theme={null}
curl -X POST https://api.example.com/v1/webhook_endpoints \
  -H "authorization: Bearer $PLATFORM_KEY" \
  -H 'content-type: application/json' \
  -d '{ "url": "https://your.app/webhooks", "enabled_events": ["invoice.stamped","invoice.cancelled"], "connect": true }'
```

Delivery body:

```json theme={null}
{
  "id": "evt_...",
  "type": "invoice.stamped",
  "created": "2026-07-10T18:00:00.000Z",
  "livemode": false,
  "account": "org_client123",
  "data": { ... the invoice ... }
}
```

A non-connect endpoint only receives the owning org's own events. (Every delivery carries
`account`; for a normal endpoint it's just the org itself.)

## Reading a connected account's event log / resources

Use the same acting-as header: `GET /v1/events -H "Invoice-Account: org_client123"`,
`GET /v1/invoices -H "Invoice-Account: org_client123"`, etc.

## Replaying a delivery

If your endpoint was down, replay an event to your endpoints with
`POST /v1/events/:id/resend`. An empty body re-fans-out to every matching endpoint; pass
`{ "webhook_endpoint_id": "we_..." }` to target one. For a connect endpoint, act with the same
`Invoice-Account` header as the account that owns the event. See [Webhooks](/guides/webhooks).
