Subi has a public REST API for reading and changing subscriptions, and webhooks that tell your own system when a subscription changes. Both use plain JSON and come with the Starter, Subi and Subi Plus plans. This page is the short version; the two references hold every field.
Your first call
On Starter, Subi or Subi Plus, create a key in the Subi app under Settings, then API keys. Send it in the X-Api-Key header. Paths end with a slash.
curl "https://api.subi.co/public/v1.0/subscription-contracts/?limit=5" \
-H "X-Api-Key: $SUBI_API_KEY"
The answer is a page of results with count, next, previous and results. A list returns 15 items unless you pass limit, up to 100, and offset moves through the rest.
Keep the key in an environment variable or your host's secret store. Do not paste it into a chat or commit it.
Keys, plans and limits
- The API and webhooks are included in the Starter, Subi and Subi Plus plans. The Free plan does not include them.
- A shop has one active key at a time. You can create, rotate or revoke it in the app. If a shop moves to a plan without the API, its active key is revoked.
- The limit is 60 requests a minute per key. Past that the API answers 429.
- MCP, which lets your own AI client read your Subi data, comes with Subi Plus or as an add-on. See building with ChatGPT, Claude or Codex.
What the API does
- Subscribers: list and fetch. You can filter by email, first name, last name and state.
- Subscription contracts: list and fetch, filtered by status, last payment status, currency, customer, billing and delivery interval, next billing date, and created or updated time.
- Actions on one contract: cancel, pause, resume, skip and reschedule. Reschedule works on plans that allow editing the next billing date.
- Contract lines:
PATCHto/public/v1.0/subscription-contracts/<id>/lines/withlines_to_swap,lines_to_update,lines_to_addorlines_to_remove. Swap, update and add each need aselling_plan_id.
What it does not do: create or delete a contract, or write to a subscriber. The API has no routes for those.
Webhooks
On Starter, Subi or Subi Plus, register an endpoint for a topic in the app under Settings, then Webhooks. Each topic can have up to five endpoints. Subi sends an HTTP POST with a JSON body when the event happens.
SUBSCRIPTION_CREATEDSUBSCRIPTION_CANCELEDSUBSCRIPTION_PAUSEDandSUBSCRIPTION_RESUMEDSUBSCRIPTION_BILLING_SUCCEEDEDandSUBSCRIPTION_BILLING_FAILED
The Test button in the app sends a WEBHOOK_TEST event so you can check your endpoint before real events arrive.
Every delivery carries X-Subi-Topic, X-Subi-Event-Id, X-Subi-Triggered-At and X-Subi-Hmac-Sha256. The last one is the base64 HMAC-SHA256 of the raw body, made with your shop's HMAC secret from the webhook settings in the app. Check it before you trust the body:
const crypto = require("crypto");
function verify(rawBody, secret, header) {
const expected = crypto.createHmac("sha256", secret)
.update(rawBody, "utf8").digest("base64");
const a = Buffer.from(expected), b = Buffer.from(header);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Answer with a 2xx within 10 seconds. A failed delivery is retried up to five times, the first retry after five minutes and each wait doubling. Use X-Subi-Event-Id to skip an event you have already handled.
The references
- Public API reference and its OpenAPI file
- Webhooks reference with every payload, and its OpenAPI file
- Both references as one markdown file for a coding agent
Stuck on a call? Write to [email protected] with the request you sent and the answer you got, and leave the key out.