App billing
/apps/billing/charges — any installation token, no scope. Billing reads nothing from the store, so there is
no permission to grant; instead the merchant approves each charge in the CIQRA admin before anything is billed.
The flow
Section titled “The flow”POST /apps/billing/charges— you describe the charge; CIQRA stores it aspendingand returns aconfirmationUrl.- Send the merchant to
confirmationUrl. They see your app, the price, the trial and the cap, and approve or decline. The link is valid for 48 hours; after that the charge isexpired. - You learn the decision from the webhook below, or by reading
GET /apps/billing/charges/{id}.
Nothing is billed before step 2. A recurring charge with a trial starts billing when the trial ends.
Create a charge
Section titled “Create a charge”{ "kind": "recurring", "name": "Pro plan", "amount": 1900, "currency": "usd", "interval": "month", "trialDays": 14 }| Field | Detail |
|---|---|
kind |
one_time, recurring or usage_capped |
name |
what the merchant sees, at most 120 characters |
amount |
minor units (cents), positive, at most 10,000,000; must be 0 for usage_capped (it has no fixed amount) |
currency |
usd, eur or try |
interval |
recurring only: month or year |
trialDays |
recurring only: 0 to 365 |
cappedAmount, terms |
usage_capped only: the ceiling the merchant approves (minor units) and what usage is billed for |
returnUrl |
optional https URL the merchant returns to after deciding |
test |
true for a test charge |
201 returns the charge: id, kind, status, amounts, test, confirmationUrl (while pending),
confirmationExpiresAt, approvedAt, billingOn (when a trial ends) and createdAt. A Stripe reference is never
returned.
Usage records
Section titled “Usage records”POST /apps/billing/charges/{id}/usage-records — Idempotency-Key required.
{ "description": "1,200 SMS sent", "amount": 2400 }The charge must be an approved usage_capped charge. A record that would take the balance past the approved
cappedAmount is refused with 422 cap_exceeded; ask for a new charge with a higher cap instead. Sending the same
Idempotency-Key again returns the first result with Ciqra-Idempotent-Replay: true and records nothing.
Cancel
Section titled “Cancel”DELETE /apps/billing/charges/{id} stops a pending, recurring or usage charge. Uninstalling your app cancels every
charge it holds.
Webhooks
Section titled “Webhooks”Subscribe your installation to app_subscriptions.update (recurring and usage charges) and
app_purchases_one_time.update (one-time charges). They need no scope and are sent only to the installation that
owns the charge — never to another app or to the merchant’s own subscriptions. Each is sent when a charge is
created, approved, declined or cancelled:
{ "chargeId": "…", "status": "active", "kind": "recurring", "name": "Pro plan", "test": true }Errors
Section titled “Errors”Every refusal has the body { "error": "…", "code": "…", "fields": { … } } (fields only for validation).
| Status | code |
Meaning |
|---|---|---|
400 |
idempotency_key_required |
a usage record was sent without Idempotency-Key |
404 |
not_found |
no such charge for this installation |
409 |
billing_not_live |
a non-test charge while paid charges are not live |
409 |
currency_mismatch |
the charge’s currency is not the currency the merchant’s store is billed in |
409 |
charge_not_active |
usage on a charge that is not approved and running |
409 |
not_cancellable |
the charge already ended |
409 |
idempotency_conflict |
the same Idempotency-Key is in flight or was used for a different record |
422 |
validation_failed |
see fields for each refused field |
422 |
cap_exceeded |
the usage record would pass the approved cap |
422 |
not_a_usage_charge |
usage sent to a one-time or recurring charge |
503 |
provider_unavailable |
the payment provider did not answer; nothing was recorded, retry with the same key |