ArcalotlArcalotl

Overview

Authenticate, paginate, and handle errors against the Arcalotl public REST API.

The Arcalotl public API gives your own systems programmatic access to the same subscriptions, plans, members, and analytics your dashboard shows: read resources, check entitlements, cancel a subscription, generate a checkout link, and subscribe to webhooks for the events that matter to you.

Base URL

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, never 403, so responses cannot be used to probe another community's data.

Authentication

Every request needs a bearer API key:

Authorization: Bearer arclt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Create and revoke keys from the dashboard: Developers -> API Keys. The full key is shown exactly once at creation time; only a display prefix (arclt_live_xxxxxxxx) is stored and shown afterward. Treat a key like a password: do not commit it, and rotate it if it leaks.

Scopes

A key carries one or more scopes chosen at creation time. A request without the scope a route requires gets a 403 with code missing_scope.

ScopeGrants
subscriptions:readList and get subscriptions
subscriptions:writeCancel a subscription
plans:readList and get plan tiers
members:readList members, look up by platform identity, read entitlements
purchases:readList and get one-time purchases
analytics:readRead the analytics summary
events:readPoll the events feed
checkout:writeCreate a hosted checkout link
webhooks:readList webhook endpoints and their deliveries
webhooks:writeCreate, update, delete, rotate, redeliver, and test webhook endpoints

Endpoints

MethodPathScopeNotes
GET/v1/subscriptionssubscriptions:readFilters: status, plan_id, tier_id, member_id. Cursor-paginated.
GET/v1/subscriptions/{id}subscriptions:read
POST/v1/subscriptions/{id}/cancelsubscriptions:writeSchedules cancellation at period end. Idempotent; supports Idempotency-Key.
GET/v1/plansplans:readPlan tiers with nested billing plans.
GET/v1/plans/{tierId}plans:read
GET/v1/membersmembers:readCursor-paginated.
GET/v1/members/{id}members:readIncludes platform identities.
GET/v1/members/lookupmembers:read?platform=discord&platform_uid=...
GET/v1/members/{id}/entitlementsmembers:readActive subscriptions and unexpired purchases resolved to tiers.
GET/v1/entitlements/checkmembers:read?platform=&platform_uid=&tier_id=. The primitive for gating access from a game server or external tool.
GET/v1/purchasespurchases:readCursor-paginated.
GET/v1/purchases/{id}purchases:read
GET/v1/analytics/summaryanalytics:readMRR, active subscribers, recent signups and cancels.
POST/v1/checkout-linkscheckout:writeCreates a hosted checkout session. Supports Idempotency-Key. See Checkout links.
GET/v1/eventsevents:readFilters: type, after_id. Cursor-paginated. See Events.
GET/v1/events/{id}events:read
GET/v1/webhooks/event-typesany valid keyMachine-readable event catalog. See Webhooks.
GET, POST/v1/webhooks/endpointswebhooks:read / webhooks:writePOST returns the whsec_ signing secret once.
GET, PATCH, DELETE/v1/webhooks/endpoints/{id}webhooks:read / webhooks:writePATCH accepts url, description, event_types, enabled.
POST/v1/webhooks/endpoints/{id}/rotate-secretwebhooks:writeReturns a new whsec_ secret once.
GET/v1/webhooks/endpoints/{id}/deliverieswebhooks:readCursor-paginated attempt log.
POST/v1/webhooks/endpoints/{id}/deliveries/{deliveryId}/redeliverwebhooks:writeRequeues a delivery for retry.
POST/v1/webhooks/endpoints/{id}/testwebhooks:writeSends a signed ping envelope synchronously. Rate-limited to 10/min per endpoint.

Pagination

List endpoints take an opaque cursor and a limit (max 100, default 25) and return a next_cursor:

{
  "data": [ ... ],
  "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wNy0wMVQxMjowMDowMFoiLCJpZCI6IjEyMyJ9"
}

next_cursor is null (or omitted) on the last page. Pass it back as cursor to fetch the next page; do not construct or parse cursor values yourself, since their internal shape is not part of the contract.

Errors

Errors are RFC 9457 application/problem+json bodies with a stable code extension member for programmatic handling:

{
  "type": "https://docs.arcalotl.com/api/errors#not_found",
  "title": "Not Found",
  "status": 404,
  "detail": "The requested resource was not found.",
  "code": "not_found"
}

Match on code, not on title or detail, which may change wording without notice.

CodeStatusMeaning
unauthorized401Missing, malformed, unknown, or revoked API key. One uniform response for all four so a response cannot be used to guess key state.
missing_scope403The key does not carry the scope the route requires.
not_found404The resource does not exist, or belongs to another community.
invalid_request400 or 422Malformed input: a bad query parameter, an unknown platform, or a body that fails validation.
conflict409The resource is not in a state that allows the requested action, or checkout eligibility fails.
payment_config_inactive409The community has no active payment provider configuration.
plan_required422The tier has more than one active plan; plan_id is required.
platform_not_connected422The community has no configuration for the requested platform.
not_eligible409The buyer is not eligible for checkout on this tier (already subscribed, already purchased, or a plan switch is required instead).
idempotency_key_reuse422The Idempotency-Key was already used for a request with a different body.
request_in_flight409A request with the same Idempotency-Key is still being processed.
endpoint_limit422The community already has the maximum of 5 webhook endpoints.
rate_limited429Rate limit exceeded. See Rate limits.
service_unavailable503An optional subsystem (webhook management) is not configured on this deployment.
internal_error500Unexpected server error.

Rate limits

The API is rate-limited per key, in addition to a lighter pre-authentication limit per client IP:

LimiterKeyDefault
AuthenticatedAPI key300 requests/min, burst 60
UnauthenticatedClient IP20 requests/min, burst 10
Webhook test-sendEndpoint10 requests/min

Every response carries rate limit headers:

RateLimit-Limit: 300
RateLimit-Remaining: 299
RateLimit-Reset: 12

A 429 additionally carries Retry-After (seconds). Back off and retry after that interval rather than polling faster.

Idempotency

POST /v1/subscriptions/{id}/cancel and POST /v1/checkout-links accept an Idempotency-Key header so a network retry cannot double-cancel a subscription or double-create a checkout session:

Idempotency-Key: a-client-generated-unique-string
  • The same key with the same request body within 24 hours replays the original response and adds Idempotent-Replayed: true.
  • The same key with a different request body returns 422 idempotency_key_reuse.
  • The same key while the first request is still being processed returns 409 request_in_flight.
  • Keys are scoped per community and per endpoint, and expire after 24 hours.

Use a fresh key per logical operation (for example a UUID you generate once per cancel button click), not a constant value.

Versioning

The API and the webhook event envelope share one version string, currently 2026-07. Within a version, changes are additive only: new fields, new optional request parameters, new event types, and new endpoints. Existing fields and endpoints do not change shape or meaning without a new version. Ignore fields you do not recognize so additive changes never break your integration.

OpenAPI spec

The full request and response contract is published as an OpenAPI 3.1 document: arcalotl-public-api.yaml.

Next steps

  • Webhooks: event envelope, the full event catalog, and signature verification.
  • Events: polling GET /v1/events for reconciliation.
  • Checkout links: sell a plan from your own systems.
  • MCP: connect an AI agent to the same API.

On this page