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.

GET/v1/credits

Credit 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.

RouteWhat it answersCredential
GET /v1/credits (this one)What the workspace can spendKey or session, dsp.usage.read
GET /v1/keys/usageWhat the calling key has spentAPI key only, dsp.usage.read
POST /v1/billing/top-up/intentsA link a person opens to buy creditsKey or session, dsp.usage.read
GET /v1/billing/top-up/intents/{topup_id}Whether that purchase has landedKey or session, dsp.usage.read
POST /v1/members/resolveWhether an email belongs to a member of your organisationKey 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 | null
expires_atstring | null
grantednumber

Credits, to at most three decimals.

remainingnumber

Credits, to at most three decimals.

reservednumberdefault: 0

Credits, to at most three decimals.

as_ofstring
metaResponseMeta

Present on every 2xx, including the ones that are not paginated.

as_ofstring
credential"api_key" | "session"default: api_key

Which 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 | null

What 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_idstring
platformstring
scope"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 | null
remainingnumber

Unrestricted grants, usable on any platform.

spendablenumber

What this tenant can spend on this platform right now.

  • spendable is the number to act on: what the workspace can spend on the data platform right now.
  • allocated is the credit set aside for the data platform: granted, remaining, reserved (held by agent runs that have not settled yet) and expires_at.
  • shared is the organisation's general credit. It is reported but cannot be spent here, so never add it to allocated.remaining.
  • scope is platform normally. tenant_wide_fallback means the billing service answered in an older shape: allocated and shared are null, and only spendable is meaningful.

Per-key spend#

curl "https://api.sproutsdata.ai/v1/keys/usage?granularity=day" \
  -H "X-API-Key: $SPROUTS_API_KEY"
granularitystringdefault: day

pattern ^(hour|day|month|total)$.

fromstring | null
tostring | null

The 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 UsageBucketOut
action_typestring | null
creditsnumber

Credits, to at most three decimals.

period_startstring
requestsinteger
granularitystring
key_idstring
metaResponseMeta

Present on every 2xx, including the ones that are not paginated.

as_ofstring
credential"api_key" | "session"default: api_key

Which 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 | null

What 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_idstring
period_fromstring
period_tostring
total_creditsnumber

What 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_requestsinteger

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.

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_atstring
metaResponseMeta

Present on every 2xx, including the ones that are not paginated.

as_ofstring
credential"api_key" | "session"default: api_key

Which 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 | null

What 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_idstring
topup_idstring

Opaque correlation id. Not a credential: it authorises nothing.

urlstring

Open this in a browser to pay. Requires a dashboard session.

  • url is the dashboard page to send the person to. Paying needs a signed-in session with billing permission.
  • expires_at is 15 minutes after the link was created.
  • topup_id is 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_idstringrequired
credits_addednumber | null

Present once status is completed, never before.

metaResponseMeta

Present on every 2xx, including the ones that are not paginated.

as_ofstring
credential"api_key" | "session"default: api_key

Which 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 | null

What 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_idstring
order_idinteger | null
status"pending" | "completed"
topup_idstring

status 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" }'
emailstringrequired

The 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.

emailstring
foundboolean

True 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.

metaResponseMeta

Present on every 2xx, including the ones that are not paginated.

as_ofstring
credential"api_key" | "session"default: api_key

Which 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 | null

What 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_idstring
rolestring | null

Their DSP role, or null if they have not been given one.

statestring

As Member.state. unknown when this email is not a member.

user_idinteger | null
  • found is true when the email belongs to a member. false is a normal answer, returned with 200, and state is then unknown.
  • role is the member's data-platform role (dsp_owner, dsp_admin, dsp_developer or dsp_viewer), or null if they have none.
  • state says whether they can use the platform:
stateMeaning
activeHas a role and has activated the platform
not_activatedHas a role, but has not activated the platform yet. Only they can do that, by signing in and accepting
invitation_pendingHas not yet accepted the invitation to the organisation
no_accessIn the organisation, with no data-platform role
unknownNot a member (found: false)

Errors#

StatusCodeSummary
401auth.unauthorizedNo usable credential (cause deliberately unspecified)
403auth.browser_originA secret key was used from a browser
403auth.insufficient_scopeThe credential does not hold the required scope
503credits.unavailableThe billing service could not confirm the charge; retry with the same Idempotency-Key
503upstream.unavailableThe retrieval engine is unreachable (not charged)
  • GET /v1/credits and GET /v1/keys/usage answer 503 credits.unavailable when the billing service cannot be reached. Retry shortly.
  • The top-up routes add 404 payment.topup_not_found (status) and 501 request.unsupported (create), described above.