Spavik
GuidesIntegrate

API conventions

Errors, retries, idempotency and pagination for API integrations.

API environment

The API is served at https://api.spavik.co, which both SDKs use by default.

The request builder on each endpoint page calls the server declared in the OpenAPI contract, with an API key sent in X-Spavik-Api-Key; see Authentication. The engine and plan catalogues are public.

Each endpoint page includes request fields, response schemas and examples. Download the OpenAPI specification to import the contract into your own tools.

The error envelope

Every error has the same shape.

{
  "status": "error",
  "message": "CREDITS_EXHAUSTED",
  "messageDetail": "Not enough credits."
}

message carries an uppercase machine code, to read in your code. messageDetail carries a readable sentence, to show or to log. Never branch your logic on messageDetail: it is prose, it can change.

The full list is on the Error codes page.

The request_id

Every response carries an X-Spavik-Request-Id header. It is the only thing worth quoting if you open a ticket: it locates the exact call in the logs.

Use the configured client and prediction inputs from Get started. SDK exceptions expose the response identifier. For REST, save the headers alongside the response body; MODEL_ID identifies your model and rows.json contains the array of prediction rows. These examples make a billable call.

from spavik import SpavikError

try:
    result = model.predict(rows)
    print(result.request_id)
except SpavikError as error:
    print(error.code, error.request_id)

Idempotency

The engine mutations that support Idempotency-Key are POST /v1/models, /predict, /outcomes, /refresh and POST /v1/forecast. Archive and restore reach the same state however often they run, so they need no key. A key is any string of up to 255 characters; a UUID is a good choice. A longer key is refused with 400 IDEMPOTENCY_KEY_TOO_LONG.

A stored successful response is replayed without another computation or charge when you reuse the original endpoint, key and payload within the retention window (24 hours by default, starting with the original request). The key must be present on the original call. After a completed record expires, the same key can execute and charge again.

The same behavior applies to every data policy, including Zero Data Retention. Successful responses are kept in a 24-hour technical cache for replay. Zero Data Retention only disables the archiving of the inputs and outputs of evaluate, backtest, forecast and predict; it does not change API bodies, parameters, responses, outcome feedback or model refresh.

# The SDK creates a key and preserves it during this call's automatic retries.
result = model.predict(rows)
print(result.predictions)

Use a unique key per logical call and preserve it across attempts. The SDKs do this for automatic retries; a fresh SDK call generates a new key.

IDEMPOTENCY_KEY_REUSED rejects different input under an existing key. REQUEST_IN_PROGRESS means the original call is still active; honor Retry-After. REQUEST_INTERRUPTED and IDEMPOTENCY_RESPONSE_UNAVAILABLE mean the outcome is uncertain: stop automatic retries, keep X-Spavik-Request-Id and inspect the request log or contact support. Do not force execution with a new key. Unresolved records remain protected rather than expiring like stored successes. See Costs and credits for the billing implications.

Pagination

Lists are walked with limit and offset, and return a pagination object.

{
  "data": [],
  "pagination": { "total": 0, "limit": 50, "offset": 0, "has_more": false }
}
RouteDefault limitMaximum
GET /v1/models50200
GET /v1/requests100500

The libraries hide all of this: models() is an iterator that fetches pages as it goes. Its limit only sets the page size; the iterator still walks every page.

for model in spavik.models(limit=50):
    print(model.id)

Time windows

Routes that read history accept from and to as ISO 8601 dates, or days for a rolling window.

ParameterDefaultMaximum
days30365

GET /v1/requests additionally accepts status=error, which keeps only failures: enough to track down a rejection that happened in production without reproducing it.

Retries

Read the error code and the contract's x-retry-policies. Retry-After, when present, supplies a delay; it does not by itself make a mutation safe to replay. Retain the original Idempotency-Key and payload for retries.

For REQUEST_INTERRUPTED or IDEMPOTENCY_RESPONSE_UNAVAILABLE, the outcome is uncertain. Do not switch to a new key or retry automatically. Inspect the request log and contact support with X-Spavik-Request-Id. CREDITS_EXHAUSTED requires credits or a plan change before retrying. See Error codes.

Rate limits

The /v1 engine routes apply no per-key request rate today. The rate_limit_per_second value in GET /v1/plans is indicative and not enforced. Plan quotas still apply: rows per prediction, context rows and active models. If a 429 TOO_MANY_REQUESTS ever reaches you, wait for Retry-After and retry with the same Idempotency-Key; the SDKs already do.

The SDKs provide bounded retries and preserve their idempotency keys within an operation. Starting a new SDK call creates a new logical operation; do not confuse it with replaying the original request.

Identifiers

They are opaque and prefixed. Do not parse them, do not rebuild them.

PrefixObject
mdl_model
ver_model version
whk_webhook
sk-spv-api-API key

Dates

Use ISO 8601 timestamps and normalize time zones consistently. Evaluation protocol timestamps are UTC; engine protocol v2 can omit the timezone suffix.

How is this guide?

Last updated on

On this page