> ## 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 operating Natural directly for a user, use the payments MCP at `https://mcp.natural.com`.
> When searching Natural documentation, use the docs MCP at `https://docs.natural.com/mcp`.
> Use the Natural CLI for terminal and CI automation.
> Use REST only for unsupported languages or when the user explicitly requests raw HTTP.
> 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.

# Manage customer access

> Manage agents across your connected customers

See which customers your agents act for, inspect what each one granted, and revoke an agent or a pending invitation whenever you need to. For the connection model, read the [Customers overview](/guides/concepts/customers).

<Snippet file="shared/prerequisites.mdx" />

## See who your agents act for

Your customers list holds every customer who has connected an agent to you. Each entry's `id` is the party ID (`pty_*`) you pass as `customerPartyId` when you act for them, and each entry shows the agents (`agt_*`) acting for that customer, with the permissions and `limits` (`perTransaction`, plus any `perDay` or `perMonth` cap you set on the agent) in force. Read it with [`GET /customers`](/api-reference/customers/list-customers).

<CodeGroup>
  ```python Python theme={null}
  from naturalpay import Natural

  client = Natural()
  customers = client.customers.list()

  for customer in customers.data:
      print(customer.id, customer.attributes.name)
  ```

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

  const client = new Natural();
  const customers = await client.customers.list();

  for (const customer of customers.data) {
    console.log(customer.id, customer.attributes.name);
  }
  ```

  ```bash CLI theme={null}
  natural customers list
  ```

  ```text MCP theme={null}
  List my active customers and the agents acting for them.
  ```

  ```bash cURL theme={null}
  curl https://api.natural.com/customers \
    -H "Authorization: Bearer $NATURAL_API_KEY"
  ```
</CodeGroup>

The response carries each customer with the agents acting for them:

<Snippet file="api-examples/customers.list.response.mdx" />

Filter by `status`: `active` (default) for every non-revoked connection, `revoked` for customers whose access ended, or `all` for both. Pending invitations are on a separate list, below. A pending invitation stays on your invitations list until the customer accepts, you revoke it, it expires, or another invitation connects the same agent and customer.

## Inspect one customer

Read a single customer with [`GET /customers/{customerId}`](/api-reference/customers/get-customer) to see exactly which agents, permissions, and limits are in force before you change anything. The `customerId` is that customer's party ID. A disconnected customer is still readable; its `delegation.status` is `REVOKED`.

<CodeGroup>
  ```python Python theme={null}
  customer = client.customers.get("pty_019cd1798d627ad9bc302511c4f2c115")

  print(customer.data.id, customer.data.attributes.agents)
  ```

  ```typescript TypeScript theme={null}
  const customer = await client.customers.get({
    customerId: "pty_019cd1798d627ad9bc302511c4f2c115",
  });

  console.log(customer.data.id, customer.data.attributes.agents);
  ```

  ```bash CLI theme={null}
  natural customers get --customer-id pty_019cd1798d627ad9bc302511c4f2c115
  ```

  ```text MCP theme={null}
  Show me customer pty_019cd1798d627ad9bc302511c4f2c115 and what my agents can do for them.
  ```

  ```bash cURL theme={null}
  curl https://api.natural.com/customers/pty_019cd1798d627ad9bc302511c4f2c115 \
    -H "Authorization: Bearer $NATURAL_API_KEY"
  ```
</CodeGroup>

The response carries the customer:

<Snippet file="api-examples/customers.get.response.mdx" />

## See pending invitations

Invitations you have sent but nobody has accepted yet live on a separate list. Read it with [`GET /customers/invitations`](/api-reference/customers/list-customer-invitations) to confirm what is still open before you revoke.

<CodeGroup>
  ```python Python theme={null}
  pending = client.customers.list_invitations()

  for invitation in pending.data:
      print(invitation.attributes.email, invitation.attributes.status)
  ```

  ```typescript TypeScript theme={null}
  const pending = await client.customers.listInvitations();

  for (const invitation of pending.data) {
    console.log(invitation.attributes.email, invitation.attributes.status);
  }
  ```

  ```bash CLI theme={null}
  natural customers list-invitations
  ```

  ```text MCP theme={null}
  Show my pending customer invitations.
  ```

  ```bash cURL theme={null}
  curl https://api.natural.com/customers/invitations \
    -H "Authorization: Bearer $NATURAL_API_KEY"
  ```
</CodeGroup>

The response carries one entry per recipient:

<Snippet file="api-examples/customers.listInvitations.response.mdx" />

Each entry's `id` is the recipient's email, and `party` is `null` until they have signed up. Each recipient groups its `agentInvitations`, one `adi_*` per agent you invited them to. You revoke by that `invitationId`.

You can invite more than one person at a customer before they connect. Once Natural identifies the recipient's customer, the invitation stays bound to that customer even if the contact later joins another party. When any one of those invitations connects an agent, Natural cancels the other pending invitations for that agent and customer with `cancelReason: CONNECTION_ESTABLISHED`. They stay canceled if access is later revoked, so reconnecting requires a fresh invitation. While the connection is active, new invitations for that agent and customer are skipped, no invitation email is sent, and the existing connection is returned in `meta.alreadyConnected`.

## Revoke a pending invitation

Cancel an invitation the recipient has not accepted with [`DELETE /customers/invitations/{invitationId}`](/api-reference/customers/revoke-customer-invitation), and they can no longer accept it. Revoking an invitation needs `delegation_invitations.delete` on your key; revoking an agent or disconnecting a customer needs `delegations.delete`, which includes it.

<CodeGroup>
  ```python Python theme={null}
  client.customers.revoke_invitation("adi_019cd1798d96adc082e235b426d4e04c")
  ```

  ```typescript TypeScript theme={null}
  await client.customers.revokeInvitation({
    invitationId: "adi_019cd1798d96adc082e235b426d4e04c",
  });
  ```

  ```bash CLI theme={null}
  natural customers revoke-invitation --invitation-id adi_019cd1798d96adc082e235b426d4e04c
  ```

  ```bash cURL theme={null}
  curl -X DELETE https://api.natural.com/customers/invitations/adi_019cd1798d96adc082e235b426d4e04c \
    -H "Authorization: Bearer $NATURAL_API_KEY"
  ```
</CodeGroup>

The invitation's `status` becomes `CANCELED` with a `cancelReason` of `DEVELOPER_REVOKED`. Revoking an invitation that is no longer `PENDING` returns 409; treat that as already done.

## Revoke an agent's access

Once a customer has accepted, you revoke per agent. [`DELETE /customers/{customerId}/agents/{agentId}`](/api-reference/customers/revoke-agent-access) strips one agent's authority over that customer immediately. `customerId` is the customer's party ID, and `agentId` is the agent you are pulling.

<CodeGroup>
  ```python Python theme={null}
  client.customers.revoke_agent(
      "pty_019cd1798d627ad9bc302511c4f2c115",
      "agt_019cd1798d637a4da75dce386343931d",
  )
  ```

  ```typescript TypeScript theme={null}
  await client.customers.revokeAgent({
    customerId: "pty_019cd1798d627ad9bc302511c4f2c115",
    agentId: "agt_019cd1798d637a4da75dce386343931d",
  });
  ```

  ```bash CLI theme={null}
  natural customers revoke-agent \
    --customer-id pty_019cd1798d627ad9bc302511c4f2c115 \
    --agent-id agt_019cd1798d637a4da75dce386343931d
  ```

  ```bash cURL theme={null}
  curl -X DELETE https://api.natural.com/customers/pty_019cd1798d627ad9bc302511c4f2c115/agents/agt_019cd1798d637a4da75dce386343931d \
    -H "Authorization: Bearer $NATURAL_API_KEY"
  ```
</CodeGroup>

Removing the last agent leaves the customer connection active with no agent grants. This preserves
connection-level consent, including subscribed lifecycle webhooks, until either party explicitly
disconnects. Revoking an agent that is already gone returns 404; treat that as already done.

## Disconnect the customer

Use [`DELETE /customers/{customerId}`](/api-reference/customers/disconnect-customer) to end the whole
connection at once from the developer side. The customer can also disconnect from their dashboard.
Send an `Idempotency-Key`; the request is rejected without it. Natural atomically revokes every
active agent grant and the customer relationship, so no agent remains authorized if the request
succeeds. Retry with the same `Idempotency-Key` to get the same response. If the response says
access cleanup is still pending, retry the request.

Disconnecting stops new activity and new connected webhook deliveries at once. Events already
delivered stay readable; undelivered ones are not exposed.

<Snippet file="shared/webhook-connect-access.mdx" />


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