SimpleKPI Logo

SimpleKPI AI › API reference

Errors and limits

Every failure from the SimpleKPI AI API comes back in the same shape, so a client only has to learn one. Successful responses are covered on theresource pages.

The error object

Errors are RFC 7807 problem details, served as application/problem+json rather thanapplication/json. Check the content type before parsing a failure as if it were the resource you asked for.

NameTypeRead OnlyMandatoryMax Len.Notes
typestringyesno Nullable. A URI identifying the kind of problem.
titlestringyesno Nullable. A short summary of the problem, the same for every occurrence of this type.
statusintegeryesno Nullable. The HTTP status code, repeated in the body.
detailstringyesno Nullable. What went wrong with this particular request.
instancestringyesno Nullable. The path that produced the error.
Status: 404 Not Found
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404,
  "detail": "No KPI with id 9999 on this account.",
  "instance": "/v1/kpis/9999"
}

Validation errors

A 400 caused by the contents of your request carries an extraerrors object, keyed by field name. That is the part worth showing someone — it says which field was wrong and why.

NameTypeRead OnlyMandatoryMax Len.Notes
typestringyesno Nullable. A URI identifying the kind of problem.
titlestringyesno Nullable. A short summary, usually "One or more validation errors occurred."
statusintegeryesno Nullable. The HTTP status code, repeated in the body.
detailstringyesno Nullable. What went wrong, when there is more to say than the field errors below.
instancestringyesno Nullable. The path that produced the error.
errorsobjectyesno Field name to the list of things wrong with it, e.g. {"aggregate_function": ["The aggregate function is case sensitive and can only be AVG or SUM."]}. This is the part worth showing a user.
Status: 400 Bad Request
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "errors": {
    "aggregate_function": [
      "The aggregate function is case sensitive and can only be AVG or SUM."
    ],
    "value_direction": [
      "The value direction is case sensitive and can only be U(p), D(own) or N(one)."
    ]
  }
}

Status codes

CodeMeaning
200The request succeeded.
201A new resource was created. The body is the resource as stored.
204The request succeeded and there is no body. Returned by every delete.
400The request was malformed, or a value failed validation. See above.
401The API key was missing, malformed, unknown, expired or revoked.
403The key is valid but lacks the scope this endpoint needs.
404No such resource on your account. Also returned when a resource exists but sits under a different parent than the one in the path.
409The request conflicts with the current state — a duplicate name, or a resource still in use.
429You are sending too fast. See below.

Two success cases are worth singling out, because the status code alone does not tell you what happened:

  • Writing a single KPI entry returns 201 for a new entry and 200 for an update. If the entry resolved but had nothing to store, 200 comes back with a stored: false object instead. See KPI Entries.
  • A batch write returns 200 even when every row was rejected. Read rows_added and rows_rejected rather than trusting the status.

Paging

List endpoints take page and rows. pagecounts from 1 and rows defaults to 500.

https://api.simplekpi.com/v1/kpientries?kpiId=1234&rows=100&page=2

Responses are plain arrays, so there is no total to read. Keep requesting pages until one comes back with fewer than rows items.

Rate limits

Two limits apply, and a request has to satisfy both. Going over either returns429 with a Retry-After header saying how long to wait.

LimitRequestsApplies to
Per client300 / 60sEvery request, including ones that fail to authenticate.
Per API key600 / 60sSustained throughput, so one busy integration cannot starve another.

Honour Retry-After rather than retrying immediately, and back off rather than looping. If you are hitting the limit on a bulk load, the fix is usually the batch endpoint — a few hundred entries in one request instead of a few hundred requests.

These limits are generous by design and may be raised. Treat them as the floor your integration should cope with, not a number to tune against.