curbed
Menu
Book a demo

Curbed API

Read your own data from your own systems.

Last updated 24 September 2026

Curbed has an API your company can use to read its own data: the reports, the figures, and the fleet and the staff as files. It is meant to make Curbed the source for the system you already have — an intranet, a lease administration, a dashboard — rather than a second system beside it.

This page is the whole documentation. It describes what exists today, not what may come.

A few fields of one report, as the API returns them.

Version 1 only reads

A key cannot create, change or delete anything. There are no POST, PATCH, PUT or DELETE addresses for keys in v1, and a key that could perform one cannot be created in the first place.

The reason is one sentence: a write made with a key has no honest author. Curbed records who did it on every report, status change and note, and a record a driver may be asked about years later is no place for an invented name.

Writes return when there is an honest answer to that. Until then we would rather say so here than after you have spent an afternoon building.

Signing in with a key

An administrator creates an API key inside Curbed itself, under Settings. The key is shown once and never again; keep it the way you keep a password, and not in a repository.

Send it with every request in the Authorization header:

Authorization: Bearer curbed_sk_7f3a9c2e…

A key belongs to your company, not to a person. It therefore cannot read another company’s data, and it keeps working when whoever created it leaves. Which rights it carries is chosen by the administrator when it is created.

If a key is lost or gets out, revoke it and create a new one. Revoking takes effect immediately. A revoked key is not erased: that a key pulled data is a fact that stays on the record.

Address and version

Everything lives under one address, and the version number is part of that address:

https://api.curbed.cab/v1

Responses are JSON, except the exports, which are CSV. Timestamps are ISO 8601 in UTC unless an endpoint says otherwise; the exports are written on your own company’s clock.

You never state which company you belong to. The key already says so, and a second place the company can be named is a second place it can be wrong.

What you can read

Every address below sits under the base URL and is a GET. The Rights column names the right the key has to carry — spelled exactly as the creation screen spells it, so you can ask your administrator for it word for word.

A key reads your whole company, across every depot. An address not listed here does not exist for a key.

Reports

EndpointRights
GET /reportsThe reports board, with the same filters, sorting and search as the screen.view_all_reports
GET /reports/{id}One report, with its vehicle, category, photos, reporter and handler.view_all_reports
GET /reports/{id}/eventsA report’s timeline as separate events, so you build the sentence in your own language.view_all_reports
GET /reports/status-countsHow many reports are open, in progress and completed.view_all_reports
GET /statsEvery figure on the statistics screen, for one period.view_all_reports

Exports (CSV)

EndpointRights
GET /export/damagesThe reports as CSV, with the same filters as the board.export_import
GET /export/carsThe fleet as CSV.export_import
GET /export/statsThe figures as CSV, in long form: section, label, value.export_import
GET /export/usersThe staff roster as CSV: email address, name and role.export_import

When something goes wrong

A failure comes back as application/problem+json (RFC 9457) carrying a fixed, machine-readable code:

{
  "type": "https://curbed.cab/problems/forbidden",
  "status": 403,
  "code": "forbidden"
}
CodeStatusMeaning
unauthenticated401No key was sent, or the header is not in the shape given above.
invalid_token401The key does not exist, has been revoked, or was mangled in transit.
forbidden403The key exists but does not carry this right. Have your administrator create a new key with the right added.
key_not_permitted403This address cannot be reached with an API key. The API is read-only: writes, and anything outside the table above, are available only to a signed-in member of staff.
invalid_id400An id in the path is not a valid uuid.
damage_not_found404No report with this id within your company.
not_found404This address does not exist. Check it against the table above.
rate_limited429This hour’s limit is used up. Retry-After says how many seconds to wait.
internal_error500Something went wrong at our end. The request was not carried out; try again, and tell us if it keeps happening.

Branch on code, never on the status. The status is there for proxies and logs; the code is the contract. There is deliberately no human explanation in the body — it would be English, and your drivers read Dutch.

A row that does not exist and a row belonging to another company answer identically. That is not sloppiness: anything else would confirm that the other company’s data exists.

How often you may ask

Each key may make 600 requests per hour. Generous for an intranet page fetching a list on load, tight for a script sitting in a loop.

Go over it and the API answers 429 with a Retry-After header giving the seconds until you may continue. Wait it out — knocking again does not shorten it.

If you genuinely need more, say for a nightly export of the whole fleet, ask. The limit is set per key and can be raised.

Worked examples

With real fleet numbers and Dutch categories, so you can see what comes back. Replace the key with your own.

The whole fleet as CSV — what you need when your intranet knows vehicles by number.

Request

curl -s https://api.curbed.cab/v1/export/cars \
  -H "Authorization: Bearer curbed_sk_7f3a9c2e…" \
  -o wagenpark.csv

Response

number,type,plate,active,location
2098,Mercedes Vito,92-NXR-3,true,Hoofdvestiging
2174,Mercedes Vito,64-KTB-8,true,Hoofdvestiging

The open reports, highest priority first.

Request

curl -s "https://api.curbed.cab/v1/reports?status=open&sort=priority&dir=desc" \
  -H "Authorization: Bearer curbed_sk_7f3a9c2e…"

Response

{
  "reports": [
    {
      "id": "c41b8e02-7d6a-4f15-b3c9-08e2a5d74169",
      "status": "reported",
      "priority": "high",
      "side": "left",
      "description": "Linker schuifdeur klemt — rubber versleten",
      "descriptionTranslated": null,
      "categoryId": "5e8a1c34-9b07-4d62-8f1a-c3d05b726e48",
      "category": { "id": "5e8a1c34-9b07-4d62-8f1a-c3d05b726e48", "name": "Carrosserie" },
      "reportedAt": "2026-09-14T06:52:11.004Z",
      "repairCostCents": null,
      "noteCount": 2,
      "car": { "id": "0f1e6a54-2c7b-4a19-9d03-6b1f7c8e4d22", "number": "2098", "plate": "92-NXR-3" },
      "photos": []
    }
  ],
  "nextCursor": null,
  "appliedStatus": "open",
  "appliedLocation": null,
  "timeZone": "Europe/Amsterdam"
}

This year’s reports as CSV, for your own reporting.

Request

curl -s "https://api.curbed.cab/v1/export/damages?status=all&from=2026-01-01" \
  -H "Authorization: Bearer curbed_sk_7f3a9c2e…" \
  -o schades.csv

Response

id,car_number,car_plate,car_type,description,category,side,priority,status,…
c41b8e02-7d6a-4f15-b3c9-08e2a5d74169,2098,92-NXR-3,Mercedes Vito,Linker schuifdeur klemt — rubber versleten,Carrosserie,left,high,reported,…
9d720f5b-3e18-4c07-a6d2-5b91f0c4e873,2174,64-KTB-8,Mercedes Vito,Ster in de voorruit bestuurderszijde,Ruitschade,front,medium,completed,…

And this is what going too fast looks like.

Request

curl -si "https://api.curbed.cab/v1/reports" \
  -H "Authorization: Bearer curbed_sk_7f3a9c2e…"

Response

HTTP/1.1 429 Too Many Requests
Retry-After: 1800
Content-Type: application/problem+json

{"type":"https://curbed.cab/problems/rate_limited","status":429,"code":"rate_limited"}

What we promise

Offering an API is a promise, not a feature. This is the promise, and it holds for everyone who has a key:

  • v1 does not break. Fields and endpoints may be added, but an existing field does not change meaning, does not change type, and does not disappear.
  • If something must break, it is called v2 and gets its own address. v1 stays alongside it for 12 months and goes on answering throughout.
  • We announce such a change by email to every company holding a live key. Not in a changelog nobody reads.

We ask one thing in return: have your integration skip fields it does not recognise rather than fail on them. Then an addition on our side is not work on yours.

In practice this means an integration you build this year still works next year, and that you will know at least 12 months ahead if that is ever going to stop being true. That is what you can budget against.

Questions

Something wrong on this page, a higher limit, or an endpoint you need that we do not have yet — email us. We are also the ones who will email you if anything about v1 ever changes.

brandon@bsquared.software

Read next

We measure how this site is used ourselves, without cookies. May we also use Google Analytics? That sets cookies and sends data to Google in the United States. Read our privacy policy