What it is for
The partner API is for reseller and technology partners. Your billing system calls it when a customer orders, moves server, upgrades or leaves. You pay wholesale: the list price minus a discount that grows with your active licences. You only ever see and change licences you issued yourself.
Base address: https://partners.respirecloud.com. Everything is JSON over HTTPS.
Getting a key
- Apply as a reseller on the partners page. We read every application and answer by e-mail.
- After approval you get an invitation to the partner portal. Set a password and an authenticator code.
- In the portal, open API keys and create a key. Give it the
readscope, andlicencesif it may issue, move, upgrade and cancel. - Copy the key at once. It looks like
rcp_<id>_<secret>and is shown once. Revoke it in the portal if it leaks; revoking takes effect at once.
API keys cannot create other keys or change payout details. Those need a portal sign-in.
Authentication
Send the key as a bearer token on every call.
curl -s https://partners.respirecloud.com/v1/partner/me \
-H "Authorization: Bearer $RC_PARTNER_KEY" The reply shows your kind, your terms and, for resellers, your active licences and current wholesale discount. Keep the key on your server, never in a browser or an app.
The licence lifecycle
Amounts are whole numbers in minor units (cents). Edition ids are the keys of /v1/partner/prices.
Issue
Send your own order id as reference. If your system retries, the same reference returns the licence that
was already issued and charges nothing. term_days defaults to 365 and is 366 at most. If the licence with
that reference was cancelled, issuing again makes a new licence and the old one gets replaced_by.
curl -s https://partners.respirecloud.com/v1/partner/licences \
-H "Authorization: Bearer $RC_PARTNER_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-issue" \
-d '{"customer": "owner@example.com", "edition": "pro", "term_days": 365, "reference": "order-1042"}' {"id": "lic_...", "key": "RC-...", "customer": "owner@example.com", "edition": "pro",
"term_end": "2027-10-30T09:00:00Z", "revoked": false, "cancelled": false,
"bound": false, "reference": "order-1042", "trial": false, "own_use": false, "billed": true,
"suspended": false}
A time that has not happened yet, such as last_seen before the first check-in, is left out of the answer.
Give the customer the key; they enter it when they activate RespireCloud.
List and read
curl -s https://partners.respirecloud.com/v1/partner/licences -H "Authorization: Bearer $RC_PARTNER_KEY"
curl -s https://partners.respirecloud.com/v1/partner/licences/lic_... -H "Authorization: Bearer $RC_PARTNER_KEY" bound is true while an installation uses the licence, and last_seen is when it last reported
(absent until it first does). Lists are newest first. ?reference=order-1042 finds the licences of one order,
newest first. Add ?limit= (100 by default, 500 at most) and ?after= to page: with either, the
answer is {"items": [...], "next": "lic_..."} and you pass next as after
until it is absent. Without them you get the plain array (the first 100) and the cursor in the
X-Next-After header. The ledger pages the same way.
Move to a new server
This frees the licence so the customer can activate it elsewhere. Moves through the API have their own limit, 100 per
rolling 30 days by default (move_limit and moves_30d on /v1/partner/me), then you
get move_limit and need to write to us. It does not use up the customer's own rebinds.
curl -s -X POST https://partners.respirecloud.com/v1/partner/licences/lic_.../move \
-H "Authorization: Bearer $RC_PARTNER_KEY" Renew
Call this each time you invoice the customer for another term. The end date moves by term_days (1 to 366)
from the later of today and the current end, and one renewal line, priced like an issue for that term (31 days books a month, not a year), goes on this month's
statement. A reference (your invoice id) makes a repeat free. Trials and own-use licences refuse with 409.
curl -s https://partners.respirecloud.com/v1/partner/licences/lic_.../renew \
-H "Authorization: Bearer $RC_PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{"term_days": 30, "reference": "invoice-7731"}' Change the edition (up or down)
A dearer edition books an upgrade line for the price difference for the days left on the licence, at your
current discount. A cheaper one books a downgrade credit: the same difference for the days left, less your
discount. An ended term earns no credit. /upgrade still works and refuses a
cheaper edition. Valid edition ids, names and prices: GET /v1/partner/editions.
curl -s https://partners.respirecloud.com/v1/partner/licences/lic_.../change \
-H "Authorization: Bearer $RC_PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{"edition": "pro"}' Suspend and unsuspend
Use these for an unpaid invoice. A suspended licence is answered suspended when the panel checks in; the
customer's sites stay up. Both calls are safe to repeat, and the licence shows suspended and
suspended_reason.
curl -s https://partners.respirecloud.com/v1/partner/licences/lic_.../suspend \
-H "Authorization: Bearer $RC_PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{"reason": "invoice 7731 unpaid"}'
curl -s -X POST https://partners.respirecloud.com/v1/partner/licences/lic_.../unsuspend \
-H "Authorization: Bearer $RC_PARTNER_KEY" Cancel
The licence stops. If you cancel in the month you issued it, that month's wholesale lines are credited. Repeating the call is safe.
curl -s -X POST https://partners.respirecloud.com/v1/partner/licences/lic_.../cancel \
-H "Authorization: Bearer $RC_PARTNER_KEY" You can hold a limited number of licences (50 unless we set another number). Cancelled licences do not count, and a trial does not count until you convert it.
Statements and prices
Each issue, renewal, upgrade, downgrade and credit is a line on the statement of that month. Totals are per currency, in
minor units. A cancel in the month of the issue is a credit line; a cheaper edition is a downgrade
line with a negative amount. The month in the address must be YYYY-MM, otherwise you get 400.
curl -s https://partners.respirecloud.com/v1/partner/prices -H "Authorization: Bearer $RC_PARTNER_KEY"
curl -s https://partners.respirecloud.com/v1/partner/statements -H "Authorization: Bearer $RC_PARTNER_KEY"
curl -s https://partners.respirecloud.com/v1/partner/statements/2026-11 -H "Authorization: Bearer $RC_PARTNER_KEY" {"pro": {"list_minor": 9900, "month_minor": 990, "currency": "USD", "discount_bps": 1500, "wholesale_minor": 8415, "wholesale_month_minor": 842}} list_minor is the yearly price; month_minor is the monthly price and is only there when the
edition has one. A term of 365 days or more books the yearly price. A shorter term books the monthly price times the
number of started 31 day periods (never more than the yearly price), or, when there is no monthly price, the yearly
price times term_days over 365, rounded up. A 31 day renewal therefore costs one month, not a year. The
same rule prices issuing, renewing, converting a trial and the difference when you change edition.
discount_bps is in hundredths of a percent, so 1500 is 15%. The first call lists the months with a summary
each; the second returns every line of one month. The figures above are an example, not a price list.
Any partner can also read /v1/partner/stats, /codes, /referrals,
/ledger and /payouts with the read scope. The customers of referrals are never shown.
Trials and your own servers
Send "trial": true when you issue to make a 14 day trial. It needs no customer e-mail, is never on your
statement and does not count for your discount tier. You may have 25 trials open at once by default (trial_cap,
409 trial_cap beyond it). To sell it, call POST /v1/partner/licences/<id>/convert
(optionally with edition and term_days), or issue the same reference again without
trial. The full wholesale line is booked that day.
Send "own_use": true for a server of your own: it is never billed and appears under own_use on
the statement at no charge. Resellers may hold one by default (own_use_licences; 409 own_use_cap
beyond it). A licence is never both. Licences show trial, own_use and billed.
GET /v1/partner/me shows your numbers: move_limit, moves_30d,
trial_cap, open_trials, own_use_licences and own_use_held. These are
current programme defaults and we can set them per partner.
Errors and limits
Every error has the same shape, with the HTTP status:
{"code": "not_found", "message": "no such licence"} | Status | Code | Meaning |
|---|---|---|
| 400 | invalid | A field is missing or wrong. Unknown fields are refused. |
| 401 | unauthorized | No valid API key or session. |
| 403 | scope | The key does not have the scope this call needs. |
| 403 | not_reseller | Affiliates have no licence API. |
| 403 | not_active | The partner account is not active. |
| 403 | session_required | Only a portal sign-in may do this, not an API key. |
| 404 | not_found | No such licence, or it is not yours. |
| 409 | issue_cap | You reached the number of licences you may issue. Ask us to raise it. |
| 409 | price_not_set | That edition has no list price yet. |
| 409 | not_an_upgrade | On /upgrade only: the new edition must cost more. Use /change to go down. |
| 409 | cancelled | The licence is cancelled. Issue it again with the same reference. |
| 409 | trial_convert_first | A trial cannot be renewed or changed. Convert it first. |
| 409 | own_use | An own-use licence is not renewed; it is not billed. |
| 409 | trial_cap | You have the most trials open that your account allows. |
| 409 | own_use_cap | You hold the most own-use licences your account allows. |
| 409 | move_limit | You moved as many licences as your account allows in 30 days. |
| 409 | moves_off | Moves through the API are switched off for your account. |
| 422 | idempotency_conflict | That Idempotency-Key was already used for a different request. |
| 429 | rate_limited | More than 600 calls a minute with one key, or too many attempts on a public or sign-in route. Retry-After says when. |
Calls with an API key are limited to 600 a minute per key. Every answer carries X-RateLimit-Limit,
X-RateLimit-Remaining and X-RateLimit-Reset (seconds); over the limit you get 429 with
Retry-After. Poll statements once a day, not every minute. The public application form allows 5 applications
an hour per address, and portal sign-in 10 attempts per 15 minutes. Errors are flat, {"code", "message"},
unlike the panel API's nested {"error": {...}}.
Safe retries
Send an Idempotency-Key header (up to 200 characters) on any write. For 24 hours the same key with the same
request returns the first answer again (marked Idempotent-Replay: true) and books nothing twice; the same key
with another request is a 422. Issue and renew also take a reference of their own.
Webhooks
The partner API sends no webhooks yet. To follow a licence, read /v1/partner/licences/<id> and
watch bound, last_seen, term_end and cancelled.
OpenAPI file
Every call, field and error as an OpenAPI 3.1 file you can load into Postman, Insomnia or a code generator: download partner-api.yaml.