Skip to main content
Most billing assumes the person who pays is the person who uses the product. Team plans break that assumption: a finance lead buys ten seats, then ten engineers each get their own license key, Discord role, or download. Seat-based pricing models that split — billing on one side, entitlements on the other — and Macropay handles the seller-of-record paperwork (global sales tax and VAT, disputes, PCI) on top.
Seat-based pricing is in private beta. Reach out to support to enable it for your organization before you build against it.

The three entities

A seat-based product introduces a layer that single-buyer products don’t have. Get these three concepts straight and every API call, webhook, and portal screen will make sense. Roles map directly to capability. Both owner and billing_manager can assign seats, change or cancel the subscription, and manage payment methods. A plain member sees only their own benefits. (The owner role may gain extra management powers later.) Here’s how it fits together for a six-seat team plan, of which four seats are in use:

Why the split is worth it

  • Members outlive any single purchase. One member can hold seats from several subscriptions or one-time orders under the same customer.
  • Entitlements attach to people, not invoices. Benefits are granted when a seat is claimed, never at checkout.
  • The portal adapts to the role. Owners and billing managers get team management; members get a personal benefits view.
The most common integration bug: reading grant.customer_id to decide who gets access. That field is always the payer. The end user lives on grant.member. Use grant.member everywhere you provision access.
The lifecycle, in one line:

What you’ll need

  • A Macropay organization with seat-based pricing enabled (private beta)
  • The latest Macropay SDK — npm install @macropayments/sdk or pip install macropay
  • Familiarity with Macropay products and subscriptions
This guide covers both subscription and one-time seat products. The assignment and claim flow is identical; only how you add seats later differs (modify the subscription vs. buy another order).

Step 1 — Create the product

1

Open Products

In the dashboard, go to Products and click Create Product.
2

Set pricing

Under Pricing:
  • Product type — Subscription (recurring) or One-time (perpetual licenses)
  • Pricing type — Seat-based
  • Min seats1, or your minimum team size
Seat pricing is volume-based: the total seat count picks a tier, and that tier’s rate applies to every seat. Buy 7 seats and you land in the 5–9 tier, so all 7 bill at that tier’s rate (7 × 9=9 = 63/mo).
3

Attach benefits

Add the benefits each seat holder receives — license keys, file downloads, Discord roles, GitHub repo access, and so on. These are granted on claim, not at purchase.

Step 2 — Checkout

Pass seats and let Macropay compute the volume price from your tiers. Because Macropay is the merchant of record, the sales tax or VAT for the buyer’s jurisdiction is calculated and remitted for you — it never lands on your tax filings.

Step 3 — Assign seats

Once the order is paid, an owner or billing manager can run seat management straight from the Customer Portal — no UI to build. The portal lets them:
  • Assign a seat to a teammate by email
  • Revoke a seat to cut access and free it for reuse
  • Resend the invite for a still-pending seat
  • Adjust the seat count on a subscription
Assigning a seat fires an invitation email with a secure claim link. The moment the teammate claims it, their benefits are granted.
The invite and claim flow is fully hosted by Macropay. Members click the link, claim the seat, and get immediate access — you don’t render or send anything.

Assigning seats from your own backend

If you already authenticate users and want to wire seats to signups, call the Customer Seats API directly:
Set immediate_claim: true when your app owns identity. It bypasses the invitation email and grants benefits on the spot — ideal for auto-provisioning a seat the instant a user joins a workspace you already control.

Step 4 — Provision on benefit grants

Listen for benefit-grant webhooks and mirror access in your own system. The recipient is grant.member; grant.customer_id is the payer.
Always verify the webhook signature before trusting an event. The handler below omits verification for brevity only.

Step 5 — Change the seat count

Subscriptions — patch the seat total:
You can’t drop below the number of assigned seats (pending plus claimed). Revoke the seats you no longer need first, then reduce the count.
One-time purchases — buy another order; each has its own independent seat pool:

Giving members the portal

To drop a member into the customer portal — to see their benefits or, for managers, to run the team — create a member session and redirect to the returned URL:
What they see depends on their role:
  • Owners and billing managers — full team management: assign seats, manage members, review utilization.
  • Members — their own benefits and account details, nothing more.

Webhook reference

Cancellations fan out. Each seat is revoked individually, so a 5-seat subscription carrying 3 benefits emits 1 + 5 + 15 = 21 events. Make every handler idempotent.

Patterns worth adopting

  • Provision off grant.member, never grant.customer_id. It’s the single most reliable way to attribute access to the right person.
  • Use seat metadata for your own bookkeeping — stash a department, cost center, or internal user ID on the seat (up to 10 keys / 1KB).
  • Tell billing managers they aren’t auto-enrolled. A manager who also wants the product must assign a seat to themselves.

Troubleshooting

Subscriptions vs. one-time

Limits

  • Seats are assigned one at a time (script the API for bulk).
  • Claim links expire after 24 hours.
  • Up to 1,000 seats per subscription.
  • Seat metadata: 10 keys, 1KB max.

Where to go next