Skip to content

Billing-sources endpoints

List billing sources

Lists the organization’s billing sources, ordered by name.

The list is not paginated, because an organization has only a few sources. No response includes an admin key; key_set says whether one is stored.

Parameter In Type Required Notes
org_id path string (uuid) yes
Status Description Body
200 Successful Response application/json: array of BillingSourceOut
422 Validation Error application/json: HTTPValidationError

POST /api/v1/orgs/{org_id}/billing-sources

Section titled “POST /api/v1/orgs/{org_id}/billing-sources”

Add a billing source

Adds a billing source and answers 201 with it.

For a source that fetches from a provider, the admin key is encrypted with CREDENTIALS_KEYS and checked once with the provider (one request, 10 seconds at most). The source is stored whatever the outcome of the check, which sets status and last_error. The key is never returned, logged or audited.

Errors: 409 NOT_CONFIGURED when the kind fetches from a provider and CREDENTIALS_KEYS is not set. 422 VALIDATION_ERROR on admin_key when the key is not an Admin API key of the kind’s provider, on provider when it contradicts the kind, and on project_ids when a project belongs to another organization. 409 BILLING_SOURCE_NAME_TAKEN when another source of the organization has the name. 409 BILLING_SOURCE_PROJECT_TAKEN when another source of the same provider already covers one of the projects. 429 RATE_LIMITED with Retry-After past five key checks in the organization, then one a minute (creates and rotations count together; a request refused before the check, a CSV source among them, spends nothing).

Parameter In Type Required Notes
org_id path string (uuid) yes

Request body (application/json, required): BillingSourceCreate

Status Description Body
201 Successful Response application/json: BillingSourceOut
422 Validation Error application/json: HTTPValidationError

DELETE /api/v1/orgs/{org_id}/billing-sources/{source_id}

Section titled “DELETE /api/v1/orgs/{org_id}/billing-sources/{source_id}”

Delete a billing source

Deletes the source with its project mappings, fetch runs and provider cost lines.

This cannot be undone, and the source’s reconciliation report stops working.

Parameter In Type Required Notes
org_id path string (uuid) yes
source_id path string (uuid) yes
Status Description Body
204 Successful Response none
422 Validation Error application/json: HTTPValidationError

GET /api/v1/orgs/{org_id}/billing-sources/{source_id}

Section titled “GET /api/v1/orgs/{org_id}/billing-sources/{source_id}”

Get a billing source

Returns one billing source. The admin key is never included.

Parameter In Type Required Notes
org_id path string (uuid) yes
source_id path string (uuid) yes
Status Description Body
200 Successful Response application/json: BillingSourceOut
422 Validation Error application/json: HTTPValidationError

PATCH /api/v1/orgs/{org_id}/billing-sources/{source_id}

Section titled “PATCH /api/v1/orgs/{org_id}/billing-sources/{source_id}”

Edit a billing source

Changes the fields sent: name, provider_scope, enabled and project_ids.

project_ids replaces the whole mapping, and provider_scope: null clears the scope. A source that is turned off is not fetched and cannot be refreshed, and its report stays readable. The name and project errors of POST apply here too.

Parameter In Type Required Notes
org_id path string (uuid) yes
source_id path string (uuid) yes

Request body (application/json, required): BillingSourceUpdate

Status Description Body
200 Successful Response application/json: BillingSourceOut
422 Validation Error application/json: HTTPValidationError

GET /api/v1/orgs/{org_id}/billing-sources/{source_id}/reconciliation

Section titled “GET /api/v1/orgs/{org_id}/billing-sources/{source_id}/reconciliation”

Reconcile a billing source with Spanlight’s figures

Compares the provider’s bill with Spanlight’s figures, per UTC day and model group.

Spanlight’s side covers the projects mapped to the source. from and to are widened to whole UTC days; the window is at most 31 days and ends today at the latest, and without them the report covers the last 14 whole days. Each day and group shows the provider’s amount, Spanlight’s amount, the explained lines and the signed residual (provider minus Spanlight minus explained). Credits and charges Spanlight cannot see are listed apart and never enter the residual. A day is provisional until 48 hours after it ends and until a successful fetch or upload that covers it finishes after that point.

Errors: 422 VALIDATION_ERROR on to when the window is longer than 31 days or ends after today (UTC), including a from later than the start of today with no to, and on from when from is not earlier than to.

Parameter In Type Required Notes
org_id path string (uuid) yes
source_id path string (uuid) yes
from query string (date-time) or null no
to query string (date-time) or null no
Status Description Body
200 Successful Response application/json: ReconciliationOut
422 The window is invalid (VALIDATION_ERROR). none

GET /api/v1/orgs/{org_id}/billing-sources/{source_id}/reconciliation.csv

Section titled “GET /api/v1/orgs/{org_id}/billing-sources/{source_id}/reconciliation.csv”

Download a billing source’s reconciliation as CSV

Returns the same report as GET …/reconciliation as a CSV file.

The file has one row per day and model group. The window rules and errors are those of the JSON report.

Parameter In Type Required Notes
org_id path string (uuid) yes
source_id path string (uuid) yes
from query string (date-time) or null no
to query string (date-time) or null no
Status Description Body
200 The report, one row per group. text/csv: any
422 The window is invalid (VALIDATION_ERROR). none

POST /api/v1/orgs/{org_id}/billing-sources/{source_id}/refresh

Section titled “POST /api/v1/orgs/{org_id}/billing-sources/{source_id}/refresh”

Fetch a billing source now

Queues a fetch of the provider’s cost report and answers 202 with the new run’s id.

The fetch covers the last seven whole UTC days, or the last 31 while the source has never been fetched successfully. Follow the run with GET …/runs.

Errors: 422 VALIDATION_ERROR on kind for a CSV source. 409 BILLING_SOURCE_DISABLED when the source is turned off. 409 NOT_CONFIGURED when BILLING_SOURCES_ENABLED is off or CREDENTIALS_KEYS is not set. 429 RATE_LIMITED with Retry-After past the limit of one refresh per source every 5 minutes, with a burst of 2. 409 BILLING_FETCH_IN_PROGRESS while another run of the source is in progress; this refusal still counts towards the limit.

Parameter In Type Required Notes
org_id path string (uuid) yes
source_id path string (uuid) yes
Status Description Body
202 Successful Response application/json: RefreshAccepted
422 Validation Error application/json: HTTPValidationError

POST /api/v1/orgs/{org_id}/billing-sources/{source_id}/rotate

Section titled “POST /api/v1/orgs/{org_id}/billing-sources/{source_id}/rotate”

Replace a source’s admin key

Replaces the admin key of a source that fetches from a provider.

The new key is encrypted and checked once, as on create, and the check sets status and last_error. Errors: 422 VALIDATION_ERROR on kind for a CSV source, which holds no key, and on admin_key when the key is not an Admin API key of the source’s provider; 409 NOT_CONFIGURED when CREDENTIALS_KEYS is not set. 429 RATE_LIMITED with Retry-After under the key-check limit of POST, which rotations share; a refused request spends nothing.

Parameter In Type Required Notes
org_id path string (uuid) yes
source_id path string (uuid) yes

Request body (application/json, required): BillingSourceRotateIn

Status Description Body
200 Successful Response application/json: BillingSourceOut
422 Validation Error application/json: HTTPValidationError

GET /api/v1/orgs/{org_id}/billing-sources/{source_id}/runs

Section titled “GET /api/v1/orgs/{org_id}/billing-sources/{source_id}/runs”

List a source’s runs

Lists the source’s fetches and uploads, newest first by start time.

Keyset pagination: limit from 1 to 100 (default 20), and cursor from the previous page’s next_cursor. A failed run’s error is an HTTP status line or a short fixed phrase, never a provider’s response body.

Parameter In Type Required Notes
org_id path string (uuid) yes
source_id path string (uuid) yes
limit query integer no min 1, max 100 Default 20.
cursor query string or null no
Status Description Body
200 Successful Response application/json: Page_BillingRunOut_
422 Validation Error application/json: HTTPValidationError

POST /api/v1/orgs/{org_id}/billing-sources/{source_id}/upload

Section titled “POST /api/v1/orgs/{org_id}/billing-sources/{source_id}/upload”

Upload a billing source’s cost CSV

Stores the lines of a cost CSV as one run of a CSV source.

Send the file as multipart/form-data in a field named file: UTF-8, at most 5 MB and 100,000 data rows, with a header that lists every column of the CSV format. The whole file is checked before anything is stored. The run covers every day from the file’s first day to its last, and for those days the report reads only this file’s lines, so a file must hold every line of each day it covers. A line already stored for its day takes the new figure. Every day must lie in the 400 days up to today (UTC), today included. A source that is turned off still accepts uploads.

Errors: 422 VALIDATION_ERROR on kind for a source that fetches from a provider. 415 UNSUPPORTED_MEDIA_TYPE when the body is not multipart/form-data. 413 PAYLOAD_TOO_LARGE over 5 MB. 429 RATE_LIMITED with Retry-After past six uploads of the source in an hour; a refused file counts. 409 BILLING_FETCH_IN_PROGRESS while another run of the source is in progress. 422 VALIDATION_ERROR with up to 20 errors[] of {field: "file", row, column, message} when the file is refused, in which case nothing is stored.

Parameter In Type Required Notes
org_id path string (uuid) yes
source_id path string (uuid) yes

Request body (multipart/form-data, required): object

Status Description Body
200 Successful Response application/json: CsvUploadOut
422 Validation Error application/json: HTTPValidationError