For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Log inGet Paid
DocumentationAPI ReferenceCLI
DocumentationAPI ReferenceCLI
  • Getting Started
    • Quickstart
    • First signals
    • Cost traces
    • Cost attributed signals
    • Delivered value
  • Credits
    • How credit balances work
    • Understanding the credit ledger
    • Examples of plans with included credits
  • Customers & Users
    • Checkout
    • User management
    • Multi-entity customers
  • Billing
    • Webhooks
    • Product lifecycle and archival semantics
    • Backdated order activation
  • Value Receipts
    • Overview
    • Integration guide
    • Authentication and embedding
  • Integrations
    • Datadog
    • Xero
LogoLogo
Log inGet Paid
On this page
  • Overview
  • How users and seats work
  • Customers, users, and seats
  • Customer
  • User
  • Seat
  • Step 1: Create the customer
  • Step 2: Create the billed seats through an order
  • Step 3: Upsert users explicitly
  • Step 4: List seats on the order
  • Step 5: Assign or unassign a single seat
  • Step 6: Assign seats in batch
  • Edge cases and behavior
  • Scheduled seat reductions
  • How users carry forward, and who loses their seat
  • Schedule, list, and cancel a reduction
  • Recommended integration flow
Customers & Users

User management

Create users explicitly, bill for seats through orders, and manage seat assignments through the public API
Was this page helpful?
Previous

Multi-entity customers

Next
Built with

Overview

Paid keeps three things separate:

  • Customers are billed.
  • Orders define how many seats exist.
  • Users can be assigned to those seats.

That separation is the important part of the model:

  • Creating or updating a user does not create billable seats.
  • Changing a seat assignment does not change billing quantity.
  • Changing billed seat count happens through the order or checkout flow.

If you understand those rules, the API is straightforward.

How users and seats work

A user is an identity within a customer account. A seat is a billable slot created from an order’s seat quantity. Users can occupy seats, but they do not create them.

This means:

  • A customer can have users without assigning them to seats yet.
  • A customer can have purchased seats that are still unassigned.
  • You increase or decrease the number of seats by changing the order, not by creating or deleting users.
  • You reflect who is using those seats by assigning or unassigning users.

In practice, most integrations use the API in this order:

  1. Create or update the customer.
  2. Create the order or checkout that defines the billed seat quantity.
  3. Upsert users by your own external IDs.
  4. List the seats created for that order.
  5. Assign or unassign users from those seats.

Customers, users, and seats

Customer

The customer is the account that owns the order and is billed for it.

User

A user is an identity within that customer. Use your own stable external IDs. You do not need to store Paid UUIDs.

Seat

A seat is created from an order’s seat-based quantity. Seats are listed and managed separately from the order.

Operationally:

  • Change the order or checkout to change billed seat count.
  • Change seat assignments to change occupancy.

Step 1: Create the customer

Create the customer that will own the users, seats, and order. See the Customers API for the full reference.

$curl -X POST https://api.paid.ai/api/v2/customers \
> -H "Authorization: Bearer $PAID_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "name": "Acme",
> "externalId": "cus_acme"
> }'

If the customer already exists, use its existing external ID in the endpoints below.

Step 2: Create the billed seats through an order

Seats come from order quantity, not from user creation.

For seat-based products, the order is the source of truth for billable seat count. The order creates the pool of seats that can later be assigned to users.

Choose one of these entry points:

  • Use checkout when the customer is purchasing or upgrading in a customer-facing flow.
  • Use direct order creation when your system provisions billing server-to-server.

When the order is created, Paid creates the seats for that order.

Step 3: Upsert users explicitly

Once the customer exists, create or update users explicitly. This keeps identity lifecycle separate from billing quantity.

Create or update a user with customer external ID and user external ID.

$curl -X PUT https://api.paid.ai/api/v2/customers/cus_acme/users/usr_123 \
> -H "Authorization: Bearer $PAID_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "name": "Jane Doe",
> "email": "jane@example.com",
> "status": "active",
> "metadata": {
> "role": "admin"
> }
> }'

Example response:

1{
2 "id": "user_01",
3 "externalId": "usr_123",
4 "customerExternalId": "cus_acme",
5 "name": "Jane Doe",
6 "email": "jane@example.com",
7 "status": "active",
8 "created": true
9}

This endpoint is idempotent. Re-sending the same user updates the existing record.

If you send "status": "deactivated" for an existing user, that user is deactivated and any current seat assignments are removed automatically.

Step 4: List seats on the order

List seats on the order to find assignable seat IDs.

$curl https://api.paid.ai/api/v2/orders/ord_01/seats \
> -H "Authorization: Bearer $PAID_API_KEY"

You can also filter by product and status:

$curl "https://api.paid.ai/api/v2/orders/ord_01/seats?productExternalId=prod_team&status=unassigned" \
> -H "Authorization: Bearer $PAID_API_KEY"

Example seat:

1{
2 "id": "6f4c8f3b-0fb8-4d90-9b0a-9f5a6d9f8c21",
3 "orderId": "ord_01",
4 "productExternalId": "prod_team",
5 "status": "assigned",
6 "assignee": {
7 "id": "user_01",
8 "externalId": "usr_123",
9 "email": "jane@example.com"
10 },
11 "createdAt": "2026-04-16T10:00:00Z"
12}

Use the seat id returned here when assigning or unassigning a seat.

Step 5: Assign or unassign a single seat

After you have both users and seats, connect them by assigning users to seat IDs.

Assign a seat to a user:

$curl -X PUT https://api.paid.ai/api/v2/orders/ord_01/seats/6f4c8f3b-0fb8-4d90-9b0a-9f5a6d9f8c21 \
> -H "Authorization: Bearer $PAID_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "userExternalId": "usr_123"
> }'

Unassign a seat:

$curl -X PUT https://api.paid.ai/api/v2/orders/ord_01/seats/6f4c8f3b-0fb8-4d90-9b0a-9f5a6d9f8c21 \
> -H "Authorization: Bearer $PAID_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "userExternalId": null
> }'

Assigning or unassigning a seat changes occupancy only. It does not change the billed quantity on the order.

Step 6: Assign seats in batch

Use batch assignment for admin tooling, bulk sync jobs, or provisioning workflows.

$curl -X POST https://api.paid.ai/api/v2/orders/ord_01/seat-assignments \
> -H "Authorization: Bearer $PAID_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "assignments": [
> { "seatId": "6f4c8f3b-0fb8-4d90-9b0a-9f5a6d9f8c21", "userExternalId": "usr_123" },
> { "seatId": "5231d4ec-e2d5-460a-9e1c-40a8d7cb0f0c", "userExternalId": "usr_456" }
> ]
> }'

You can also unassign in batch by setting "userExternalId": null on any entry.

Edge cases and behavior

  • A user must belong to the same customer as the order.
  • Deactivated users cannot be assigned to seats.
  • Assigning a user to a new seat for the same seat-based line should not silently duplicate occupancy.
  • Unassigning a seat does not reduce what the customer is billed for.
  • Creating a user does not automatically create new billed seats.

Scheduled seat reductions

Seat reductions can be scheduled to take effect at the next billing anchor rather than immediately. This avoids mid-cycle proration and gives users time to wind down before they lose access.

When a reduction is scheduled, two things are written:

  • The current seat-bearing line is marked to end at the anchor.
  • A new line with the lower seat quantity is created, effective from the anchor.

Until the anchor passes, GET /orders/{id}/seats returns the existing seats (full quantity, current assignments). After the anchor, it returns the new (lower) quantity. Assignments carry forward automatically. Users on the existing line are migrated onto the new line’s seats at the first read past the anchor, so the same users remain assigned without any action from the integrator.

How users carry forward, and who loses their seat

The carry-forward is first-in, first-out by assignment time: users whose updatedAt on the seat is oldest are kept; users whose seat was most-recently assigned are dropped if the new quantity is too small. This protects long-tenured assignments.

To prevent dropped users at the anchor, the schedule endpoint rejects requests where the number of assigned users on the line is already greater than the new quantity. Callers must unassign users themselves before scheduling the reduction. This check is enforced only at schedule time, however: assignments made on the existing line after the reduction is scheduled but before the anchor passes can still push the count above the new quantity. If that happens, the most-recently-assigned users lose their seat at the anchor.

Recommendation: surface the pending reduction in your own UI and discourage assigning new users to seats on an order with a scheduled reduction.

Schedule, list, and cancel a reduction

The scheduled-change endpoints are not yet listed in the API reference. Reach out to your account team to enable them on your organisation.

Recommended integration flow

For most integrations, the lifecycle looks like this:

  1. Upsert the customer when the account is created in your product.
  2. Create the initial order or checkout when the customer purchases seats.
  3. Upsert users whenever users are invited, imported, or changed in your app.
  4. Assign those users to seats as part of provisioning.
  5. Update the order when the customer buys more or fewer seats.