StackSpendDocs

API Reference

Use the StackSpend REST API to pull cost line items, pre-aggregated rollups, and anomaly alerts into your own tooling.

Overview

The StackSpend API is a REST API hosted at https://api.stackspend.com. All endpoints are versioned under /api/v1/.

Every response is wrapped in a standard envelope:

{
  "data":  { ... },   // payload — object or array
  "error": null,      // null on success; error object on failure
  "meta":  { ... }    // pagination cursors, request metadata
}
Business plan required.API access is available on the Business plan and above. Requests from free or Starter plan workspaces will receive a PLAN_RESTRICTED error.

Rate limits

The default limit is 60 requests per minute per API key. Exceeding this returns a 429 RATE_LIMITED error. Contact support@stackspend.com to request a higher limit.

Authentication

Authenticate by passing your API key in the X-API-Key header, or as a Bearer token in the Authorization header. Both forms are accepted.

# Using X-API-Key header
curl -H "X-API-Key: your_key" \
  "https://api.stackspend.com/api/v1/public/line-items?start_date=2025-01-01&end_date=2025-01-31"

# Using Authorization: Bearer
curl -H "Authorization: Bearer your_key" \
  "https://api.stackspend.com/api/v1/public/line-items?start_date=2025-01-01&end_date=2025-01-31"

Creating API keys

Go to Settings → API in your StackSpend workspace, then click Create key. The secret is shown once at creation — copy it immediately and store it securely. You cannot retrieve it again after closing the dialog.

Scopes

Each key carries one or more scopes. Calling an endpoint without the required scope returns INVALID_SCOPE.

ScopeGrants access to
line_items:readGET /api/v1/public/line-items
rollups:readGET /api/v1/public/rollups/daily
anomalies:readGET /api/v1/public/anomalies
usage:writePOST /api/v1/otel-ingest (OpenTelemetry ingest)

GET /api/v1/public/line-items

Scope: line_items:read

Returns cursor-paginated raw cost line items for the requested date range. Each record corresponds to one billed line item from a connected provider.

Query parameters

ParameterRequiredDescription
start_dateYesStart of date range (YYYY-MM-DD, inclusive)
end_dateYesEnd of date range (YYYY-MM-DD, inclusive)
limitNoRecords per page. Integer 1–1000, default 50.
cursorNoOpaque cursor from meta.next_cursor of the previous page.

Example response

{
  "data": [
    {
      "id": "li_01hxyz",
      "usage_date": "2025-01-15",
      "provider_type": "openai",
      "provider_service": "gpt-4o",
      "net_amount_usd": 12.48,
      "currency_original": "USD",
      "project_id": "proj_abc123",
      "user_email": "alice@example.com"
    }
  ],
  "error": null,
  "meta": {
    "next_cursor": "eyJpZCI6ImxpXzAxaHh5eiJ9",
    "has_more": true
  }
}

Pagination

When meta.has_more is true, pass meta.next_cursor as the cursor query parameter of your next request. Repeat until has_more is false.

GET /api/v1/public/rollups/daily

Scope: rollups:read

Returns pre-aggregated daily cost totals. Faster than fetching raw line items when you only need summary-level data for charts or dashboards.

Query parameters

ParameterRequiredDescription
start_dateYesStart of date range (YYYY-MM-DD, inclusive)
end_dateYesEnd of date range (YYYY-MM-DD, inclusive)
group_byYesDimension to group by: provider, service, or category

Example request

curl -H "X-API-Key: your_key" \
  "https://api.stackspend.com/api/v1/public/rollups/daily?start_date=2025-01-01&end_date=2025-01-31&group_by=provider"

Example response

{
  "data": [
    {
      "date": "2025-01-15",
      "cost_usd": 248.30,
      "provider_type": "aws",
      "service": null,
      "category": null
    },
    {
      "date": "2025-01-15",
      "cost_usd": 87.12,
      "provider_type": "openai",
      "service": null,
      "category": null
    }
  ],
  "error": null,
  "meta": {}
}

GET /api/v1/public/anomalies

Scope: anomalies:read

Returns anomaly alerts detected by StackSpend's ML models. Use this endpoint to sync alerts into your own incident management or on-call tooling.

Query parameters

ParameterRequiredDescription
limitNoMaximum records to return (default 50, max 500)
sinceNoISO 8601 timestamp — only return anomalies detected after this time
provider_typeNoFilter by provider slug (e.g. openai, aws)
severityNolow | medium | high | critical
statusNonew | acknowledged | resolved | false_positive | dismissed

Example response

{
  "data": [
    {
      "id": "anom_09abc",
      "provider_type": "openai",
      "service": "gpt-4o",
      "detected_date": "2025-01-16T08:23:00Z",
      "actual_cost": 340.12,
      "expected_cost": 95.00,
      "deviation_percent": 258.0,
      "severity": "critical",
      "alert_type": "spend_spike",
      "status": "new"
    }
  ],
  "error": null,
  "meta": {}
}

Error codes

All errors use the same envelope shape. The HTTP status code and error.code field tell you what went wrong:

{
  "data": null,
  "error": {
    "code": "RATE_LIMITED",
    "message": "You have exceeded 60 requests per minute. Retry after 30 seconds."
  },
  "meta": {}
}
CodeHTTP statusMeaning
UNAUTHORIZED401No API key provided, or the key is malformed.
FORBIDDEN403Key is valid but has been revoked or deleted.
INVALID_SCOPE403Key does not have the scope required by this endpoint.
PLAN_RESTRICTED403Workspace is not on a plan that includes API access.
VALIDATION_ERROR422A required parameter is missing or has an invalid value.
RATE_LIMITED429Too many requests. Back off and retry after the indicated delay.
INTERNAL_ERROR500Unexpected server error. Retry with exponential backoff; contact support if it persists.

Related

API Reference — StackSpend Docs — StackSpend Docs