Developers

The Arcalotl API

A public REST API and signed webhooks over the same subscriptions, members, entitlements and analytics your dashboard shows. Scoped keys, cursor pagination, idempotent writes and problem-details errors.

Every Arcalotl community has a public API at https://api.arcalotl.com/v1. Your own systems can read subscriptions, plan tiers, members, entitlements, purchases, discount codes and analytics, create checkout links, switch, cancel and reactivate subscriptions, open the member portal for a member, and manage webhook endpoints.

Webhooks push the same events the API serves, signed to the Standard Webhooks specification, so your service can react to a payment or a revoked entitlement without polling. The events feed exists as well, for reconciliation after downtime.

The API is included in the product price. Arcalotl charges $0/month plus 2% of each successful payment, taken on the creator's own Stripe account through Stripe Connect direct charges. There is no developer tier and no per-call charge.

  • One base URL, scoped per community

    All resources live under https://api.arcalotl.com/v1. Every resource is scoped to the community that owns the API key used to call it. An id that belongs to another community answers 404 rather than 403, so responses cannot be used to probe another community's data.

  • Bearer API keys with explicit scopes

    Each request carries an Authorization header with a bearer key created in the dashboard under Developers, then API Keys. A key holds the scopes chosen at creation time, and a request without the scope a route requires returns 403 with the code missing_scope. The full key is shown exactly once at creation; only a display prefix is stored afterwards.

  • Reads cover the whole billing picture

    GET endpoints return subscriptions with status, plan and tier filters, plan tiers with their nested billing plans, members with their platform identities, a member's resolved entitlements, one-time purchases, discount codes with redemption counts, and an analytics summary with MRR, active subscribers and recent signups and cancels.

  • Writes are few and deliberate

    Writes cover the whole subscription lifecycle: create a checkout link for a specific buyer, switch a subscription between plans, cancel it at period end or reactivate it, open the member portal for a member, attach your own user id to a member, and manage webhook endpoints. Checkout links accept a connected platform identity, an existing member id, or a namespaced external user id you own, which is how an operator-controlled application sells through Arcalotl.

  • Pagination is cursor based

    List endpoints take an opaque cursor and a limit, with a maximum of 100 and a default of 25, and return a next_cursor. The field is null or absent on the last page. Pass the value back verbatim; the internal shape of a cursor is not part of the contract, so do not construct or parse one.

  • Idempotency keys make retries safe

    Cancel and checkout-link requests accept an Idempotency-Key header. The same key with the same body within 24 hours replays the original response and adds Idempotent-Replayed: true. The same key with a different body returns 422 idempotency_key_reuse, and reusing it while the first request is still running returns 409 request_in_flight. Generate a fresh key per logical operation.

  • Errors are RFC 9457 problem documents

    Failures return application/problem+json with a stable code member, for example unauthorized, missing_scope, not_found, invalid_request, conflict, not_eligible or rate_limited. Match on code. The title and detail fields are human-readable and their wording can change without notice.

  • Rate limits are published in every response

    Authenticated traffic is limited per key at 300 requests per minute with a burst of 60. Requests with a missing or invalid key are limited per client IP at 20 per minute with a burst of 10, and do not affect successfully authenticated calls. Every response carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset, and a 429 adds Retry-After in seconds.

  • Webhooks follow the Standard Webhooks specification

    Each delivery carries webhook-id, webhook-timestamp and webhook-signature headers. The signature is HMAC-SHA256 over the id, the timestamp and the raw body joined by dots, keyed with the decoded part of your whsec_ secret. Verify against the raw body before parsing JSON, accept any one of the space-separated v1 tokens so secret rotation works, and reject a timestamp more than five minutes from your clock.

  • Delivery is at least once, with retries and auto-disable

    Any 2xx counts as success. Anything else retries on a fixed schedule of roughly ten attempts spread over about 2.3 days before the delivery is marked exhausted. An endpoint with ten consecutive exhausted deliveries is disabled automatically, and any success resets that counter. A community can register up to five HTTPS endpoints, inspect the attempt log, and requeue a specific delivery.

  • The events feed covers what webhooks miss

    GET /v1/events returns the same envelopes your endpoints receive, newest first, filterable by type and by after_id so you can track a checkpoint instead of a timestamp. Projected events are kept for 90 days and delivery logs for 30, so you can reconcile long after a delivery log has aged out.

  • Changes within a version are additive only

    The API and the webhook envelope share one version string. Within a version you get new fields, new optional parameters, new event types and new endpoints, and existing fields do not change shape or meaning. Ignore fields you do not recognize and additive changes will never break your integration.

  • The contract is published as OpenAPI 3.1

    The full request and response contract is an OpenAPI 3.1 document served from the site, and the API reference pages are generated from that same document, so the reference cannot drift from the spec your code generator reads.

API key scopes

ScopeGrants
subscriptions:readList and get subscriptions
subscriptions:writeSwitch plans, cancel, and reactivate
plans:readList and get plan tiers
members:readList members, look up by platform identity or your own user id, read entitlements
members:writeAttach your user ids, open the member portal, issue link codes
purchases:readList and get one-time purchases
analytics:readRead the analytics summary
events:readPoll the events feed
discounts:readList discount codes and their usage
checkout:writeCreate a checkout link
webhooks:readList webhook endpoints and their deliveries
webhooks:writeCreate, update, delete, rotate, redeliver and test endpoints

Choosing between webhooks, the events feed and MCP

Use webhooks when your service can expose an HTTPS receiver and needs to act quickly on a change. Verify the signature, deduplicate on the envelope id, and return a 2xx fast. Treat the envelope as a signal: its data is a snapshot from the moment the event was projected, so re-fetch the resource when you need current truth.

Use the events feed when you cannot expose a receiver, or when you are recovering from downtime. Poll with after_id from your last processed event, page until the cursor is empty, then advance your checkpoint.

Use the MCP server when the consumer is an AI agent rather than a service. It exposes the same reads and the same checkout-link write as tools, enforces the same scopes, and calls the same internal service the REST handlers call.

For an application that enforces access itself, subscribe to member.entitlement.granted, updated and revoked. Those events come from the authoritative entitlement ledger and carry a stable key and an increasing revision, which is what you want for an authorization system.

Questions

Read next

Build on your own billing data

Create a scoped API key in the dashboard, point it at https://api.arcalotl.com/v1, and register a webhook endpoint for the events you care about.

Create an account