API overview
One shape for every call, how keys pick the mode, idempotency, rate limits and errors.
Shape
Every operation is POST /v1/<resource>.<verb> with a JSON body and a JSON answer.
curl https://revenue.api.corplandtechnologies.com/v1/balances.check \
-H "Authorization: Bearer rv_sk_test_..." \
-H "Content-Type: application/json" \
-d '{ "customer_id": "user_123", "feature_id": "videos" }'The most used operations also answer at short names: check, track, attach, checkout (preview an attach) and cancel.
Keys
| Prefix | Mode | Can call |
|---|---|---|
rv_sk_test_ | Test | Everything |
rv_sk_live_ | Live | Everything |
rv_pk_test_, rv_pk_live_ | Matching mode | plans.list, plans.get, features.list and features.get only, safe in a browser |
Test and Live never share customers, balances or plans. Build in Test, then press Copy to Live on the Plans page.
Idempotency
Send Idempotency-Key as a header (or idempotency_key in the body) on anything that writes. Keys are kept 24 hours per mode and operation. The SDK adds one to every write so its retries are safe.
| Situation | Answer |
|---|---|
| First request | Runs normally |
| Same key, same body | 409 idempotency_replay, with the first answer in data.response |
| Same key, different body | 409 idempotency_mismatch |
| Same key while the first is still running | 409 idempotency_in_progress |
| First request failed with a 5xx | The key is released; retry freely |
Treat idempotency_replay as success.
Rate limits and billing locks
Each key may send 2,000 requests a second to check, track and the other usage calls, and 100 a second to everything else. Over the limit you get 429 rate_limited with Retry-After: 1. Billing changes for one customer run one at a time; a second change that arrives while the first is running gets 429 billing_busy.
Errors
Every error is { "message": "...", "code": "...", "data"?: {...} } with a matching HTTP status.
| Status | Common codes |
|---|---|
| 400 | missing_feature_id, invalid_amount, currency_mismatch, customer_email_required, paystack_not_connected, max_purchase_exceeded, missing_fx_rate |
| 401 | invalid_api_key |
| 402 | insufficient_balance, spend_limit_reached, max_purchase_reached, usage_limit_reached, no_access |
| 403 | secret_key_required |
| 404 | customer_not_found, plan_not_found, feature_not_found, entity_not_found, subscription_not_found, unknown_operation |
| 409 | idempotency_replay, idempotency_mismatch, idempotency_in_progress, balance_contention, plan_already_attached, lock_exists, lock_finalized, already_redeemed |
| 429 | rate_limited, billing_busy |
| 5xx | Retry with backoff, and fail open in the meantime |
Operations
| Resource | Operations |
|---|---|
| Customers | customers.get_or_create, customers.get, customers.update, customers.delete, customers.list |
| Catalog | features.list, features.get, features.create, features.update, features.delete, plans.list, plans.get, plans.create, plans.update, plans.delete, plans.versions, plans.migrate |
| Billing | billing.attach, billing.preview_attach, billing.update, billing.preview_update, billing.setup_payment, billing.open_customer_portal, billing.cancel |
| Balances | balances.check, balances.track, balances.batch_track, balances.track_tokens, balances.finalize, balances.create, balances.update, balances.delete, balances.grant, balances.list |
| Entities | entities.create, entities.get, entities.update, entities.delete, entities.list |
| Invoices and usage | invoices.list, invoices.get, invoices.void, invoices.mark_paid, payment_methods.list, payment_methods.delete, events.list, events.aggregate |
| Rewards | rewards.create, rewards.list, rewards.get, rewards.update, rewards.delete, rewards.redeem, referrals.create_program, referrals.list_programs, referrals.get_program, referrals.update_program, referrals.delete_program, referrals.create_code, referrals.redeem |
| Costs | costs.track, costs.batch_track, costs.list, costs.rates.list |
| Analytics | analytics.overview, analytics.margins, analytics.advisor |