Documentation Index
Fetch the complete documentation index at: https://docs.actionlayer.dev/llms.txt
Use this file to discover all available pages before exploring further.
| Method | Path | Purpose |
|---|
GET | /v1/billing/subscription | Read current plan, usage, limits, resource counts |
POST | /v1/billing/checkout | Create a Stripe Checkout session for upgrade |
POST | /v1/billing/portal | Create a Stripe Customer Portal session |
The subscription endpoint reads only from the database — ActionLayer never queries Stripe in real time for plan enforcement.
Get subscription
curl https://api.actionlayer.dev/v1/billing/subscription \
-H "Authorization: Bearer $ACTIONLAYER_API_KEY"
Response
{
"plan": "pro",
"plan_status": "active",
"beta_override": false,
"trial_ends_at": "2026-05-30T00:00:00Z",
"current_period_start": "2026-04-01T00:00:00Z",
"current_period_end": "2026-05-01T00:00:00Z",
"emails_sent_this_period": 142,
"inbound_received_this_period": 318,
"identity_count": 3,
"rule_count": 7,
"domain_count": 1,
"limits": {
"emails_per_period": 5000,
"inbound_per_period": 10000,
"max_identities": 10,
"max_rules": 25,
"max_domains": 3
}
}
Fields
| Field | Notes |
|---|
plan | One of builder_pack, pro, agency. (agency is the Business tier in marketing copy.) |
plan_status | Stripe-mirrored: trialing, active, past_due, canceled |
beta_override | If true, plan limits are bypassed (manual flag set by support; checked first in enforcement) |
trial_ends_at | Null if not on a trial |
current_period_* | Stripe billing period; for Builder Pack these are null and quotas are lifetime |
emails_sent_this_period | Outbound counter — for Builder Pack this is a lifetime total that never resets |
inbound_received_this_period | Inbound counter |
identity_count / rule_count / domain_count | Live counts for the workspace |
limits | The cap for each metric on the current plan |
Plans & limits
| Plan | Price | Outbound | Inbound | Identities | Rules | Domains |
|---|
| Builder Pack | Free | 50 lifetime | 50 lifetime | 1 | 0 | 1 |
| Pro | $29/mo | 5,000/mo | 10,000/mo | 10 | 25 | 3 |
Business (agency in API) | $79/mo | 15,000/mo | 30,000/mo | 50 | 100 | 10 |
Builder Pack quotas are a lifetime cap, not a monthly allowance — the counter never resets. Designed for evaluation, not production.
Create checkout session
Initiate an upgrade. Returns a Stripe Checkout URL with a 30-day trial; card is required upfront.
curl -X POST https://api.actionlayer.dev/v1/billing/checkout \
-H "Authorization: Bearer $ACTIONLAYER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"plan": "pro", "interval": "monthly"}'
Request body
| Field | Values |
|---|
plan | pro | agency |
interval | monthly | annual |
Response
{ "checkout_url": "https://checkout.stripe.com/c/pay/cs_…" }
Redirect the user to checkout_url. On completion they land back at app.actionlayer.dev/billing?session_id=…. The Stripe webhook updates plan and plan_status server-side; the dashboard re-reads /billing/subscription to display the new state.
Create billing portal session
Lets the user manage their subscription, payment method, and invoices.
curl -X POST https://api.actionlayer.dev/v1/billing/portal \
-H "Authorization: Bearer $ACTIONLAYER_API_KEY"
Response
{ "portal_url": "https://billing.stripe.com/p/session/…" }
Plan-limit errors
When you exceed a quota, write endpoints return 402 with an upgrade_url:
{
"error": "plan_limit_reached",
"message": "Outbound quota reached for this billing period.",
"upgrade_url": "https://app.actionlayer.dev/billing"
}
beta_override: true skips this check — useful for design-partner workspaces.
Errors
| HTTP | error | When |
|---|
| 422 | invalid_plan | plan not in {pro, agency} |
| 422 | invalid_interval | interval not in {monthly, annual} |
| 422 | stripe_customer_missing | The workspace’s Stripe customer hasn’t been created yet — retry shortly |
| 502 | stripe_error | Upstream Stripe API failure |