Endpoints
Credits, top-ups and members
Your workspace's credit balance, a key's spend, top-up links a person can pay through, and resolving an email to a member.
/v1/creditsCredit balance for the tenant
What this tenant can spend on the data platform.
All three numbers are real now that grants carry a platform_code (SDP-15):
- allocated — credits earmarked to dsp specifically. - shared — the tenant's unrestricted credits. Reported but not spendable here: dsp is hard-capped (SDP-30), so an exhausted allocation is a 402 rather than a quiet fall-through onto the Account OS balance. It is reported anyway because an empty allocation beside a healthy shared balance must read as "move some across", not as an empty account. - spendable — the headline, and the one that agrees with what a charge will actually allow.
scope says which of those two worlds produced the answer, so a caller can tell a real per-platform figure from the legacy tenant-wide fallback that an un-upgraded mint still returns.
Scope: dsp.usage.read
Use it when an integration needs to know whether it can afford the next call, which key is spending, how to ask a person to buy more credits, or who in the organisation it is working for. Outcome: the numbers and handles your code needs, from routes that are all free to call.
| Route | What it answers | Credential |
|---|---|---|
GET /v1/credits (this one) | What the workspace can spend | Key or session, dsp.usage.read |
GET /v1/keys/usage | What the calling key has spent | API key only, dsp.usage.read |
POST /v1/billing/top-up/intents | A link a person opens to buy credits | Key or session, dsp.usage.read |
GET /v1/billing/top-up/intents/{topup_id} | Whether that purchase has landed | Key or session, dsp.usage.read |
POST /v1/members/resolve | Whether an email belongs to a member of your organisation | Key or session, dsp.search.read or dsp.agents.write |
These routes describe the reference contract. For how credits work, what each call costs and how buying works, read Balance and spend and Buying credits.
Balance#
This endpoint takes no parameters.
allocatedAllocatedCredits | nullexpires_atstring | nullgrantednumberCredits, to at most three decimals.
remainingnumberCredits, to at most three decimals.
reservednumberdefault: 0Credits, to at most three decimals.
as_ofstringmetaResponseMetaPresent on every 2xx, including the ones that are not paginated.
as_ofstringcredential"api_key" | "session"default: api_keyWhich credential produced this response. session means the dashboard playground ran it as the signed-in user rather than as an API key — so it is billed to the user, subject to interactive rate limits, and carries no integration compatibility guarantee. Additive and defaulted, so it breaks no existing client.
credits_chargednumber | nullWhat this request cost, in credits, to at most three decimals. 0 when it cost nothing: a Basic or AI search that found nothing, rows this search already paid for (a cursor sent again, or a request repeated with the same Idempotency-Key on the same UTC day), or a test key. A request without a cursor or a repeated key is a new search, so keep the first page rather than asking for it again. null on a free endpoint.
environment"live" | "test"Echoed on every response so a developer can never mistake a test-key result for a live one.
request_idstringplatformstringscope"platform" | "tenant_wide_fallback"tenant_wide_fallback means mint cannot yet attribute grants to a platform, so only spendable is answerable — allocated and shared are null. They are deliberately null rather than filled with the tenant-wide totals, which are not this platform's to report.
sharedSharedCredits | nullremainingnumberUnrestricted grants, usable on any platform.
spendablenumberWhat this tenant can spend on this platform right now.
spendableis the number to act on: what the workspace can spend on the data platform right now.allocatedis the credit set aside for the data platform:granted,remaining,reserved(held by agent runs that have not settled yet) andexpires_at.sharedis the organisation's general credit. It is reported but cannot be spent here, so never add it toallocated.remaining.scopeisplatformnormally.tenant_wide_fallbackmeans the billing service answered in an older shape:allocatedandsharedarenull, and onlyspendableis meaningful.
Per-key spend#
curl "https://api.sproutsdata.ai/v1/keys/usage?granularity=day" \
-H "X-API-Key: $SPROUTS_API_KEY"granularitystringdefault: daypattern ^(hour|day|month|total)$.
fromstring | nulltostring | nullThe calling key's own spend, bucketed by granularity (hour, day, month
or total; default day). from defaults to 30 days before to, and to
defaults to now.
This route answers for an API key only, because a dashboard session has no key of its own. To see runs from a session, use usage history.
bucketsarray of UsageBucketOutaction_typestring | nullcreditsnumberCredits, to at most three decimals.
period_startstringrequestsintegergranularitystringkey_idstringmetaResponseMetaPresent on every 2xx, including the ones that are not paginated.
as_ofstringcredential"api_key" | "session"default: api_keyWhich credential produced this response. session means the dashboard playground ran it as the signed-in user rather than as an API key — so it is billed to the user, subject to interactive rate limits, and carries no integration compatibility guarantee. Additive and defaulted, so it breaks no existing client.
credits_chargednumber | nullWhat this request cost, in credits, to at most three decimals. 0 when it cost nothing: a Basic or AI search that found nothing, rows this search already paid for (a cursor sent again, or a request repeated with the same Idempotency-Key on the same UTC day), or a test key. A request without a cursor or a repeated key is a new search, so keep the first page rather than asking for it again. null on a free endpoint.
environment"live" | "test"Echoed on every response so a developer can never mistake a test-key result for a live one.
request_idstringperiod_fromstringperiod_tostringtotal_creditsnumberWhat the ledger charged, in credits to at most three decimals. A call is charged once its response is built, so one that failed first cost nothing.
total_requestsintegerTop-up links#
An API key can never buy credits, but it can hand a person a link to buy them. The full flow is in Buying credits.
Create a link
curl -X POST "https://api.sproutsdata.ai/v1/billing/top-up/intents" \
-H "X-API-Key: $SPROUTS_API_KEY"This endpoint takes no parameters.
Takes no body: the person picks the amount in the browser, and the workspace comes from your credential.
expires_atstringmetaResponseMetaPresent on every 2xx, including the ones that are not paginated.
as_ofstringcredential"api_key" | "session"default: api_keyWhich credential produced this response. session means the dashboard playground ran it as the signed-in user rather than as an API key — so it is billed to the user, subject to interactive rate limits, and carries no integration compatibility guarantee. Additive and defaulted, so it breaks no existing client.
credits_chargednumber | nullWhat this request cost, in credits, to at most three decimals. 0 when it cost nothing: a Basic or AI search that found nothing, rows this search already paid for (a cursor sent again, or a request repeated with the same Idempotency-Key on the same UTC day), or a test key. A request without a cursor or a repeated key is a new search, so keep the first page rather than asking for it again. null on a free endpoint.
environment"live" | "test"Echoed on every response so a developer can never mistake a test-key result for a live one.
request_idstringtopup_idstringOpaque correlation id. Not a credential: it authorises nothing.
urlstringOpen this in a browser to pay. Requires a dashboard session.
urlis the dashboard page to send the person to. Paying needs a signed-in session with billing permission.expires_atis 15 minutes after the link was created.topup_idis a correlation id only. It authorises nothing, so it is safe to show in a chat or a log.
A deployment with no dashboard to send people to answers
501 request.unsupported.
Check whether it was paid
curl "https://api.sproutsdata.ai/v1/billing/top-up/intents/{topup_id}" \
-H "X-API-Key: $SPROUTS_API_KEY"Path parameters
topup_idstringrequiredcredits_addednumber | nullPresent once status is completed, never before.
metaResponseMetaPresent on every 2xx, including the ones that are not paginated.
as_ofstringcredential"api_key" | "session"default: api_keyWhich credential produced this response. session means the dashboard playground ran it as the signed-in user rather than as an API key — so it is billed to the user, subject to interactive rate limits, and carries no integration compatibility guarantee. Additive and defaulted, so it breaks no existing client.
credits_chargednumber | nullWhat this request cost, in credits, to at most three decimals. 0 when it cost nothing: a Basic or AI search that found nothing, rows this search already paid for (a cursor sent again, or a request repeated with the same Idempotency-Key on the same UTC day), or a test key. A request without a cursor or a repeated key is a new search, so keep the first page rather than asking for it again. null on a free endpoint.
environment"live" | "test"Echoed on every response so a developer can never mistake a test-key result for a live one.
request_idstringorder_idinteger | nullstatus"pending" | "completed"topup_idstringstatus is pending until the purchase lands, then completed, with
credits_added and order_id. Reading the status does not use it up, so poll
every few seconds. An unknown or expired topup_id, or one from another
workspace, answers 404 payment.topup_not_found: start a new top-up.
Resolve a member#
curl -X POST "https://api.sproutsdata.ai/v1/members/resolve" \
-H "X-API-Key: $SPROUTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "ada@example.com" }'emailstringrequiredThe email to look up. Matched case-insensitively. There is no tenant_id field on purpose — the organisation is the credential's own, never the caller's choice. ≤ 320 chars.
Checks one email address against your own organisation's members, for an integration (Sprouts in Slack, for example) that has to link a person to their Sprouts account before it spends the organisation's credits. The organisation is always the credential's own: there is no field to name another one. The email is matched without regard to case.
emailstringfoundbooleanTrue when this email belongs to a member of the credential's organisation. False is an answer, not an error — this route returns 200 for 'not a member', and reserves every non-2xx for 'could not determine'. A client that conflates the two will either refuse a colleague whenever auth-service blinks, or admit a stranger when it does.
metaResponseMetaPresent on every 2xx, including the ones that are not paginated.
as_ofstringcredential"api_key" | "session"default: api_keyWhich credential produced this response. session means the dashboard playground ran it as the signed-in user rather than as an API key — so it is billed to the user, subject to interactive rate limits, and carries no integration compatibility guarantee. Additive and defaulted, so it breaks no existing client.
credits_chargednumber | nullWhat this request cost, in credits, to at most three decimals. 0 when it cost nothing: a Basic or AI search that found nothing, rows this search already paid for (a cursor sent again, or a request repeated with the same Idempotency-Key on the same UTC day), or a test key. A request without a cursor or a repeated key is a new search, so keep the first page rather than asking for it again. null on a free endpoint.
environment"live" | "test"Echoed on every response so a developer can never mistake a test-key result for a live one.
request_idstringrolestring | nullTheir DSP role, or null if they have not been given one.
statestringAs Member.state. unknown when this email is not a member.
user_idinteger | nullfoundistruewhen the email belongs to a member.falseis a normal answer, returned with200, andstateis thenunknown.roleis the member's data-platform role (dsp_owner,dsp_admin,dsp_developerordsp_viewer), ornullif they have none.statesays whether they can use the platform:
state | Meaning |
|---|---|
active | Has a role and has activated the platform |
not_activated | Has a role, but has not activated the platform yet. Only they can do that, by signing in and accepting |
invitation_pending | Has not yet accepted the invitation to the organisation |
no_access | In the organisation, with no data-platform role |
unknown | Not a member (found: false) |
Errors#
| Status | Code | Summary |
|---|---|---|
| 401 | auth.unauthorized | No usable credential (cause deliberately unspecified) |
| 403 | auth.browser_origin | A secret key was used from a browser |
| 403 | auth.insufficient_scope | The credential does not hold the required scope |
| 503 | credits.unavailable | The billing service could not confirm the charge; retry with the same Idempotency-Key |
| 503 | upstream.unavailable | The retrieval engine is unreachable (not charged) |
GET /v1/creditsandGET /v1/keys/usageanswer503 credits.unavailablewhen the billing service cannot be reached. Retry shortly.- The top-up routes add
404 payment.topup_not_found(status) and501 request.unsupported(create), described above.