Developer API
Curobi has a read-only HTTP API for pulling your subscription data into whatever else you run — a warehouse, an ERP, a CRM, a BI dashboard, a nightly reconciliation script — and signed outbound webhooks so those systems are told when something happens instead of polling for it.
https://app.curobi.com/api/admin/v1The Developer API and outbound webhooks are a Pro feature, and they share one entitlement — the API is what you ask, webhooks are what you’re told, and a merchant with one and not the other has half an integration. See Pricing & Plans.
Minting keys, the bearer header, the scope list, and what happens on uninstall.
Authentication & scopesEvery v1 endpoint, pagination, rate limits, and versioning.
Admin API referenceAsynchronous CSV and JSONL exports: datasets, filters, signed downloads, retention.
Export jobsThe error envelope and every code the API can return.
ErrorsEndpoint setup, signature verification, retries, and the event catalogue.
WebhooksThe cart-line property contract for build-a-box, Mix & Match, and gifts.
Headless & custom storefrontsQuickstart
Confirm you’re on Pro
The API is checked against your plan on every request, not just when the key is minted. A
Starter shop’s key is refused with plan_upgrade_required even if the key itself is perfectly
valid.
Mint a key
In your Curobi admin, open API keys, name the key after the system that will use it, and tick only the scopes that system needs.
The key is shown once. It’s stored as a salted hash and is not recoverable — if you lose it, revoke it and mint another.
Call the API
Every request is a plain HTTPS GET with one header, so any HTTP client will do.
cURL
curl -sS "https://app.curobi.com/api/admin/v1/subscriptions?status=ACTIVE&limit=100" \
-H "Authorization: Bearer $CUROBI_API_KEY"Every list endpoint answers with the same two-key envelope:
{
"data": [ { "contract_id": "gid://shopify/SubscriptionContract/1234", "status": "ACTIVE" } ],
"next_cursor": "eyJ0IjoiMjAy…"
}Every tab above reads the key from the server’s environment, and that is the point. A secret
key is a full-power read credential — it must never reach a browser bundle, a mobile app, a theme
file or a committed .env. There is no browser-safe Curobi credential yet; the publishable key
(curobi_pk_…) is reserved for a Storefront API that has not shipped.
Register a webhook endpoint
So you stop polling. Either from the Webhooks page in your Curobi admin, or over the API with a
manage:webhooks key — see Webhooks.
What exists today
| Surface | Status | What it does |
|---|---|---|
Admin API — /api/admin/v1 | ✅ Available | Server-to-server reads over subscriptions, plans, bundles, Mix & Match, gifts, win-back, notifications and analytics, behind a secret key |
| Outbound webhooks | ✅ Available | Fifteen signed lifecycle events pushed to your endpoint, with retries and a delivery log |
| Headless purchase path | ✅ Available | Needs no Curobi credential at all — see Headless & custom storefronts |
| Subscription writes | Planned | Pause, resume, cancel, reschedule and line edits over the API. The write:* scopes are published vocabulary, not working endpoints |
Export jobs — /api/admin/v1/exports | ✅ Available | Asynchronous CSV and JSONL exports as jobs: ask, poll, fetch a signed download |
| Storefront & Customer APIs | Planned | Browser-safe publishable keys and a headless customer portal |
v1 is read-only, with exactly two exceptions: webhook endpoint management under
manage:webhooks, and POST /exports. Everything else answers 405 method_not_allowed to a
POST, PUT, PATCH or DELETE. An endpoint is part of the API’s own plumbing, and an export
queues a read of rows the key could already page through — so neither can change a contract, a
plan, or a price.
Two limits worth knowing before you design around them
Curobi can only see contracts Curobi created. The app holds Shopify’s
read_own_subscription_contracts / write_own_subscription_contracts scopes, so a subscription
another app created is invisible to this API even on a store where Curobi is installed. This is a
Shopify permission boundary, not a Curobi decision. To bring old subscriptions across, use the
CSV import, which creates real Curobi-owned contracts.
The data is a mirror, not the ledger. Every value the API returns is Curobi’s local copy of what Shopify last said. Shopify owns the contract and the money. Reconcile against Shopify before you bill anything against these figures.
Conventions at a glance
Cursor-based, opaque cursors, { data, next_cursor }.
One envelope, a stable code, and a request_id on every response.
- Versioning is in the path (
/v1) and additive-only. New fields may appear; existing fields never change meaning and are never removed. Parse defensively — an unknown field is not an error. - Rate limits are per shop: 60 requests/minute sustained, burst 120.
- Request ids (
X-Curobi-Request-Id) are on every response. Quote one in a support request and we can find the exact call. - Protected Customer Data — names, email addresses and gift messages — comes back only to a key
holding
read:customers, and never over webhooks at any scope.