Skip to content

Billing & payouts

Endpoints for two separate things: billing is what you pay to Sidedoor for your subscription and add-ons; payouts is what Sidedoor pays out to your venues’ bank accounts from guest payments. Every endpoint is operator (client role) and scoped to your own account - send an Authorization: Bearer token from the Authentication flow. Amounts are integer pence (or minor currency units). Card and bank details are always returned pre-redacted - brand and last 4 digits only, never a full card or account number.

Method Path Purpose Auth
GET /api/my-billing/plan Plan tiers, your current plan and bundled add-ons operator
POST /api/my-billing/plan Change plan operator
GET /api/my-billing/addons Your add-on selections and metered usage operator
POST /api/my-billing/addons Change an add-on’s tier operator
GET /api/my-billing/payment-method Card or Direct Debit, whichever you pay with operator
PUT /api/my-billing/payment-method Switch which rail you pay by operator
GET /api/my-billing/card Your saved subscription card operator
POST /api/my-billing/card/setup-intent Start capturing a new card operator
POST /api/my-billing/card/default Set the saved card as default operator
POST /api/my-billing/gocardless/setup Start setting up a Direct Debit mandate operator
POST /api/my-billing/gocardless/refresh Re-check a mandate’s live status operator
GET /api/my-billing/upcoming A live preview of your next invoice operator
GET /api/my-billing/invoices List invoices operator
GET /api/my-billing/invoices/:id One invoice, with its line items operator
GET /api/my-billing/invoices/:id/pdf Download one invoice as a PDF operator
GET /api/my-operator/payout/accounts Your Stripe Connect payout accounts operator
GET /api/my-operator/payout/groups Which venues pay out to which account operator
GET /api/my-payouts List payouts operator
GET /api/my-payouts/summary Payout totals (paid out, in transit, failed) operator
GET /api/my-payouts/:payoutId/breakdown What one payout is made up of operator

GET /api/my-billing/plan returns every plan tier with its price and bundled add-ons, your current plan, any scheduled plan change, and complimentary add-ons granted to your account free of charge. GET /api/my-billing/addons returns your actual add-on selections and this period’s metered usage per channel (email, SMS, push, Aimy tokens).

Terminal window
curl "https://thesidedoor.co/api/my-billing/plan" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
curl "https://thesidedoor.co/api/my-billing/addons" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"plan": "growth",
"pending_plan": null,
"currency": "gbp",
"plans": [{ "id": "growth", "base_price_pence": { "gbp": 9900 }, "bundled_addons": ["bi_advanced"] }],
"complimentary": []
}
{
"addons": { "bi_advanced": { "active": true }, "aimy": { "active": true, "pending": false } },
"usage": { "email": { "used": 3800, "allowance": 10000 }, "aimy_tokens": { "used": 1200, "allowance": 5000 } },
"period": "2026-07"
}

POST /api/my-billing/plan changes plan - send { "plan": "growth" } with one of the plan ids from the GET above. An upgrade applies immediately; a downgrade is scheduled for the start of your next billing period and shows up as pending_plan until then. POST /api/my-billing/addons changes a single add-on’s tier - send { "addon": "aimy", "package_key": "standard" }. Enabling an add-on (or upgrading its tier) applies immediately; disabling it (or downgrading) is scheduled for next period in the same way.

Terminal window
curl -X POST "https://thesidedoor.co/api/my-billing/plan" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"plan": "growth"}'
curl -X POST "https://thesidedoor.co/api/my-billing/addons" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"addon": "aimy", "package_key": "standard"}'
{ "ok": true, "plan": "growth" }

A scheduled downgrade instead returns { "ok": true, "scheduled": true, "effective_at": "2026-08-01" }.

{ "ok": true, "addon": "aimy", "package_key": "standard", "allowance": 5000, "price_pence": 2900 }

A scheduled change (a downgrade or turning an add-on off) instead returns { "ok": true, "scheduled": true, "effective_at": "2026-08-01" }.

GET /api/my-billing/payment-method returns which rail your subscription is paid by - card or direct_debit - with the state of each. GET /api/my-billing/card returns just the card half: hasCard, and if true, its brand and last4.

Terminal window
curl "https://thesidedoor.co/api/my-billing/payment-method" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"method": "card",
"card": { "hasCard": true, "brand": "visa", "last4": "4242" },
"directDebit": { "mandate": false, "status": null }
}

PUT /api/my-billing/payment-method switches which rail your subscription collects from - send { "method": "direct_debit" } or { "method": "card" }. You need a card already saved, or a set-up Direct Debit mandate, before you can switch to it.

To save a new card, POST /api/my-billing/card/setup-intent starts a Stripe Elements capture and returns a client_secret to confirm client-side; once Stripe confirms it, the card is saved automatically. POST /api/my-billing/card/default then marks a saved payment_method id (from the Stripe confirmation) as the one to charge. To start Direct Debit instead, POST /api/my-billing/gocardless/setup returns an authorisationUrl - redirect the operator there to set up the mandate with GoCardless - and POST /api/my-billing/gocardless/refresh re-checks the mandate’s live status once they’re back.

Terminal window
curl -X PUT "https://thesidedoor.co/api/my-billing/payment-method" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"method": "direct_debit"}'
curl -X POST "https://thesidedoor.co/api/my-billing/card/setup-intent" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
curl -X POST "https://thesidedoor.co/api/my-billing/gocardless/setup" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{ "ok": true, "method": "direct_debit" }
{ "client_secret": "seti_...", "publishable_key": "pk_live_..." }
{ "authorisationUrl": "https://pay.gocardless.com/flow/..." }

GET /api/my-billing/upcoming computes a live preview of your next invoice - nothing is saved or charged by reading it. GET /api/my-billing/invoices lists past invoices (search with q, filter with status, sort with sort/dir). GET /api/my-billing/invoices/:id reads one invoice with its line items.

Terminal window
curl "https://thesidedoor.co/api/my-billing/upcoming" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
curl "https://thesidedoor.co/api/my-billing/invoices?limit=20" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{ "period": "2026-08", "lines": [{ "kind": "plan", "description": "Growth plan", "amount_pence": 9900 }], "total_pence": 9900 }
{
"data": [{ "id": "inv_1", "number": "INV-1042", "status": "paid", "total_pence": 9900, "issued_at": "2026-07-01T00:00:00Z" }],
"balancePence": 0,
"suspended": false
}

A single invoice adds lines: [{ "kind": "plan", "description": "Growth plan", "quantity": 1, "unit_pence": 9900, "amount_pence": 9900 }].

GET /api/my-billing/invoices/:id/pdf streams the invoice as a PDF (Content-Type: application/pdf). It returns 404 if a PDF hasn’t been generated yet for that invoice.

Terminal window
curl "https://thesidedoor.co/api/my-billing/invoices/INVOICE_ID/pdf" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN" \
-o invoice.pdf

GET /api/my-operator/payout/accounts lists the Stripe Connect accounts your payouts go to. GET /api/my-operator/payout/groups shows which venues are routed to which account, for operators with more than one.

Terminal window
curl "https://thesidedoor.co/api/my-operator/payout/accounts" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{ "accounts": [{ "id": "pacc_1", "label": "Main account", "status": "enabled", "is_default": true, "connected": true }] }
{ "groups": [{ "id": "pgrp_1", "label": "Main account", "venue_ids": ["ven_123", "ven_456"] }], "venues": [{ "id": "ven_123", "name": "The Attic" }] }

GET /api/my-payouts lists payouts with search (q), filters (status, from, to, venue) and sort (sort/dir); add ?format=csv to download the filtered set as a file. GET /api/my-payouts/summary returns just the totals. GET /api/my-payouts/:payoutId/breakdown reconciles one payout into the sales, refunds and adjustments it’s made up of.

Terminal window
curl "https://thesidedoor.co/api/my-payouts?status=paid&limit=25" \
-H "Authorization: Bearer $SIDEDOOR_TOKEN"
{
"data": [
{ "id": "po_1", "amount_minor": 420000, "fee_minor": 1200, "net_minor": 418800, "currency": "gbp", "status": "paid", "arrival_date": "2026-07-18", "bank_last4": "6789", "bank_name": "Example Bank" }
]
}
{ "paid_out": 4200000, "in_transit": 420000, "failed": 0, "payout_fees": 12000, "payouts": 42 }
{
"data": {
"payout_id": "po_1",
"amount_minor": 420000,
"gross_minor": 430000,
"refunds_minor": 10000,
"venues": [{ "id": "ven_123", "name": "The Attic" }],
"sales": [{ "category": "deposits", "amount_minor": 300000 }],
"adjustments": []
}
}