Endpoints
All endpoints are read-only (GET) and live under /api/v1.
Tenant
`GET /me`
Returns the authenticated creator's basic info and current plan.
Leads
`GET /leads`
List leads (users captured via your storefront/forms) ordered by created_at desc. By default, leads that have converted into customers or are archived are excluded.
Query params:
limit(default 50, max 200)cursor— opaque, from previous responsemeta.next_cursorcreated_after,created_before— ISO 8601 timestampsinclude_converted— settrueto include leads withconverted_at != null(former leads who became paying customers). Useful when you sync the full history into a CRM.include_archived— settrueto include contacts the creator soft-archived from their dashboard. Use this when syncing the full history to a CRM that needs to delete or unsubscribe the matching record on its side.
Each lead includes:
id,source— acquisition surface (e.g.storefront_login,blog_lead_capture,free_signup)created_at,converted_at(null when still a lead),archived_at(null when active)user—id,email,name,first_name,last_name,phone. All exceptidandemailcan be null when the contact was captured through a flow that didn't collect them. CRMs that expect first/last separately (HubSpot, Mailchimp, ConvertKit) can map directly.marketing_consent— see Marketing consent object below.
`GET /leads/:id`
Retrieve a single lead, including converted_at, archived_at, and marketing_consent. Returns the row even after conversion or archive (so CRM dereferences keep working).
Customers
`GET /customers`
List users with at least one purchase from your store. Archived customers are excluded by default; pass ?include_archived=true to include them.
Each customer includes id, email, name, first_name, last_name, phone, created_at, and the same marketing_consent object as leads. Name fields may be null when not collected at checkout.
`GET /customers/:id`
Retrieve a single customer. Includes:
acquisition—source,acquired_at,converted_atif the customer started as a lead (null otherwise).marketing_consent— see below.
Marketing consent object
Returned on every lead and customer payload. Always present (defaults to { status: "none", ...all-null } for contacts who never interacted with consent).
{
"marketing_consent": {
"status": "granted" | "withdrawn" | "none",
"granted_at": "2026-06-02T10:00:00.000Z" | null,
"withdrawn_at": "2026-06-15T14:30:00.000Z" | null,
"source": "auth_modal_storefront" | "...",
"policy_version": "2026-06-01" | null
}
}Status semantics:
granted—granted_atset,withdrawn_atnull. Only contacts in this state can receive marketing emails.withdrawn—withdrawn_atset. Do not send marketing communications, even if re-syncing later overwrites your CRM-side flag.none— no consent record. Treat the same aswithdrawnfor marketing purposes.
Source values (which surface captured the latest action):
| Source | Where the consent was given |
|---|---|
auth_modal_storefront | Sign-in modal on the storefront landing page |
auth_modal_blog_lead | Sign-in modal opened from a blog-post lead-capture button |
auth_modal_lesson | Sign-in modal on a course lesson page |
auth_modal_product | Sign-in modal on a product page |
auth_modal_app | Sign-in modal on a course/blog app presentation page |
auth_modal_checkout | Sign-in modal on the checkout init page |
blog_lead_section | Inline Subscribe widget rendered inside a blog post (no modal hop — signed-in user) |
storefront_lead_section | Inline Subscribe widget rendered as a storefront LEAD_CAPTURE item (signed-in user) |
free_signup_checkout | Free-product checkout form |
paid_checkout | Stripe-hosted paid checkout (recorded by the tenant webhook after checkout.session.completed) |
account_settings | The contact toggled the subscription themselves on /client/account |
creator_initiated | The creator (or team admin) unsubscribed the contact on their behalf — typically after an external request (GDPR Art. 21). Distinguishes proactive opt-outs from user-initiated ones for audit purposes. |
`policy_version` — version label of the consent wording shown to the contact at the moment they granted consent. Bumped when the wording changes materially. Stored so you can prove which legal text the contact agreed to.
Products
`GET /products`
List your products with active pricing options.
`GET /products/:id`
Retrieve a single product.
Orders
`GET /orders`
List purchases (one-time + recurring) across all your products.
Query params include the standard pagination/date filters plus:
status—ACTIVE,CANCELLED,EXPIRED,REFUNDED,FREE_TRIAL,PENDING_CHECKOUTproduct_id— filter to a specific product
`GET /orders/:id`
Retrieve a single order.
Subscriptions
`GET /subscriptions`
Like /orders but filtered to recurring purchases only. Same query params.
Analytics
`GET /analytics/summary`
Returns aggregated metrics for a period.
Query params:
period_start,period_end— ISO 8601 (default: last 30 days)
Response includes:
orders_count,paying_orders_countleads_countunique_customersconversion_rate(unique customers / leads, or null)revenue_by_currency— array withcurrency,gross_revenue_cents,aov_centsper currency
Events
`GET /events`
Unified feed of recent events across your store. Use this to drive webhook-style integrations via polling.
Use the cursor from the previous response and poll every 5–15 minutes. Do not poll more often than once every 5 minutes unless the creator's plan explicitly allows it.
Event types:
lead.created—data:lead_id,customer_id,sourcelead.converted— emitted when a lead becomes a paying customer.occurred_atis the conversion timestamp.data:lead_id,customer_id,sourceorder.completedsubscription.cancelledaccess.granted
Each event has id, type, occurred_at, and a data object specific to the type.