OpenAPI YAMLOpenAPI JSONproblems YAMLAPI overview
This group has 6 operations, generated from api/openapi.yaml. Filter by path, action, or authentication. Each endpoint lists its inputs; expand it for a request template and response codes. Templates need your own values and a schema-valid body.
Replace uppercase placeholders with your values. For a JSON request, save a body matching the schema in request.json. Cookie examples use a local cookie jar from an authenticated session.
Plans, credit balances and statements
Get Billing Balance
The calling project's source-aware balance snapshot. All millicredit amounts are canonical decimal strings. It is a snapshot, not authority to pay; rails_available is false while card, tax and cash-out rail are unavailable.
Parameters
| Name | Send in | Required? | Description |
|---|---|---|---|
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
Request template and responses
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/billing/balance'Responses
| Status | Meaning | Body and headers |
|---|---|---|
| 200 | Balance snapshot. | BillingBalance (application/json) |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |
Get Billing Statement
Stable cursor pagination over immutable posted journal entries for the calling project. Holds are not posted entries. Corrections link to the original event instead of rewriting it. There is no arbitrary grant or payout mutation on this surface.
Parameters
| Name | Send in | Required? | Description |
|---|---|---|---|
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| cursor | query | optional | |
| limit | query | optional |
Request template and responses
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/billing/statement'Responses
| Status | Meaning | Body and headers |
|---|---|---|
| 200 | Statement page. | BillingStatement (application/json) |
| 400 | invalid_request - limit is out of range. | Problem (application/problem+json) |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |
Get Billing Usage
The calling project's use for one UTC month, with the bytes served and received (never charged), the storage charged above the free storage of the payer's plan (allowance.storage_bytes), and the API requests, billed project stream events and webhook delivery attempts counted against the free 10,000 a month. A project paying for itself reads its own pool.
A project another payer pays for shares that payer's pool with the payer's other projects; it reads its own share, and payer names the payer. The payer's pool total stays on the payer's billing reads.
Parameters
| Name | Send in | Required? | Description |
|---|---|---|---|
| ScreenRig-Project | header | optional | Deprecated for one release. Must be consistent with the JWT projects grants; adds Deprecation and Warning headers. No token exchange. |
| period | query | optional | UTC month in YYYY-MM form; defaults to the current month. |
Request template and responses
curl --request GET --header 'Authorization: Bearer [SCREENRIG_TOKEN]' --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/billing/usage'Responses
| Status | Meaning | Body and headers |
|---|---|---|
| 200 | Project usage. | ProjectBillingUsage (application/json); headers: Cache-Control |
| 400 | invalid_request - period is not a UTC month in YYYY-MM form. | Problem (application/problem+json) |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |
Get App Store Offer
What an organization may buy through the App Store in the screenRIG iPhone and iPad app (bundle ai.screenrig.app), and the account token its purchases carry.
Requires a designated admin of the live organization (the person who manages its plan and billing); staff and the admins of the reseller the organization is delegated to may read the offer without products or token, and anyone else answers 404 not_found.
An organization delegated to a reseller lists no products: its reseller pays for its plan. account_token is a random UUID the server creates once per organization and keeps: the app passes it to StoreKit as appAccountToken, so every transaction and server notification names its organization.
It is the all-zero UUID for a reader who cannot buy. products lists the plans the caller may buy now, one App Store product each: plus, education (only while education_eligible is true) and premium. education_eligible is true when staff verified a K-12 school or district, or when the admin reading the offer has a verified account email address at a K-12 school domain (education_eligibility_source school_email): opening the offer, or recording a transaction, as such an admin makes the organization eligible once, writes an organization audit entry naming the matched domain, and includes Education in the same offer.
A staff decision, either way, is final and automatic eligibility never overrides it.
A plan the organization already holds through another source (staff, invoicing, another subscription) at the same or a higher level is not offered, except to the person whose App Store subscription holds it, who may change plans within the subscription group. can_purchase is true when products is not empty. subscription is the organization's App Store subscription, or null.
Response is private and no-store.
Parameters
| Name | Send in | Required? | Description |
|---|---|---|---|
| organization_id | path | required |
Request template and responses
curl --request GET --cookie cookies.txt --cookie-jar cookies.txt 'https://screenrig.ai/api/organizations/ORGANIZATION_ID/app-store/offer'Responses
| Status | Meaning | Body and headers |
|---|---|---|
| 200 | The organization's App Store plan offer. | AppStoreOffer (application/json); headers: Cache-Control |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |
Record App Store Transaction
Records one StoreKit 2 signed transaction (Transaction.jwsRepresentation) bought for the organization and puts the organization on its plan. Requires a designated admin of the live organization, same-origin cookie authentication and, for JWT sessions, the CSRF header.
The server verifies the JWS with its x5c chain to Apple Root CA - G3 (outside production also Xcode's StoreKit testing root), the bundle id ai.screenrig.app, the product id, the environment (Production on production only; Sandbox everywhere, because App Review and TestFlight buy with sandbox accounts against production; Xcode outside production only) and that appAccountToken equals the organization's account_token (getAppStoreOffer); nothing in the request names who paid.
The plan follows the product of the newest transaction of the subscription: a higher plan applies at once and a lower one when billing's next UTC month boundary reaches it, as for any plan change. Sending a transaction again, or an older one, changes nothing and answers the subscription as it stands; an expired transaction is recorded and changes no plan.
The app finishes the transaction after a 2xx or a definitive 4xx problem. Problems: app_store_transaction_invalid (422), app_store_account_mismatch (409), education_not_eligible (403), app_store_plan_conflict (409), billed_by_reseller (409, the organization is delegated to a reseller, which pays for its plan).
Parameters
| Name | Send in | Required? | Description |
|---|---|---|---|
| organization_id | path | required |
Request body fields
| Field | Description |
|---|---|
| signed_transaction (required, string) | The transaction's StoreKit 2 jwsRepresentation, exactly as StoreKit returned it. minLength: 1 maxLength: 65536 |
Request template and responses
curl --request POST --cookie cookies.txt --cookie-jar cookies.txt --header 'Content-Type: application/json' --data '@request.json' 'https://screenrig.ai/api/organizations/ORGANIZATION_ID/app-store/transactions'Responses
| Status | Meaning | Body and headers |
|---|---|---|
| 200 | The App Store subscription after the transaction. | AppStoreSubscription (application/json); headers: Cache-Control |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |
Receive App Store Notification
Apple's App Store Server Notifications V2 (the signedPayload body), the URL set in App Store Connect for the production and sandbox environments. Public: the signed payload is the credential, verified the way recordAppStoreTransaction verifies a transaction, together with the signed transaction and renewal info inside it.
SUBSCRIBED, DID_RENEW, DID_CHANGE_RENEWAL_PREF and DID_CHANGE_RENEWAL_STATUS (and OFFER_REDEEMED, RENEWAL_EXTENDED and REFUND_REVERSED) apply the newest transaction: a renewal extends the subscription, an upgrade moves the plan at once and a downgrade when the lower product is renewed at period end.
EXPIRED, GRACE_PERIOD_EXPIRED, REFUND and REVOKE end the subscription and remove the plan it set, as billing removes any plan: at the next UTC month boundary, taking nothing already granted back. A plan staff or invoicing put on the organization since is never removed.
Any other type, a notification for a product that is not a plan, and one that names no organization are acknowledged and logged. 200 acknowledges. A payload that does not verify is a 422 app_store_transaction_invalid problem; a failure on the server's side is a 5xx, which Apple sends again. Limited per client address.
Request body fields
| Field | Description |
|---|---|
| signedPayload (required, string) | Apple's signed notification (a JWS). minLength: 1 |
Request template and responses
curl --request POST --header 'Content-Type: application/json' --data '@request.json' 'https://api.screenrig.ai/api/app-store/notifications'Responses
| Status | Meaning | Body and headers |
|---|---|---|
| 200 | The notification was acknowledged. | AppStoreNotificationAcknowledgement (application/json); headers: Cache-Control |
| 422 | app_store_transaction_invalid — the payload is not a valid App Store notification for this server. | Problem (application/problem+json) |
| 429 | Stable rate_limited problem. Retry only after the authoritative Retry-After interval. Fixed-window denials also include the applicable RateLimit-Policy and RateLimit members; concurrency and byte-budget denials omit those optional disclosures. | Problem (application/problem+json); headers: Retry-After, RateLimit-Policy, RateLimit |
| default | Stable RFC 9457 problem response. A 421 server_draining carries Retry-After of 1 second, a 500 not_ready or dependency_unavailable carries 5, and a 500 manifest_degraded carries 60, unless the handler set a more specific value. | Problem (application/problem+json) |