Documentation Reference

All topics

API for other systems Admins

Read the register from other systems and report where assets are.

mapzaa has an HTTP API, so a system that is not mapzaa can read the register and help keep it true. It is deliberately narrow. A key can read everything its organisation owns, and it can report where an asset is. Nothing else.

Reading is for anything that wants the register without scraping the dashboard: a report, a map of your own, a works system that needs to know what stands where. Reporting a position is for anything that knows better than the map where something has got to — a tracker on a vehicle, a sensor on a container, a phone in somebody's hand, a survey that corrected a hundred coordinates at once. Most of a register stands still, and a bench put somewhere once stays there; the API is here for the part of it that does not.

Getting a key

  1. Go to Settings › API keys and press Create key. Only administrators see the page.
  2. Name it after the system it belongs to, not after what it is. Works management system and Plough trackers, winter 25/26 are both things you can revoke a year later without having to guess.
  3. Choose what it may do. Read only lists and looks up assets. Read and report where assets are also moves pins. Give a key the narrower of the two whenever that will do.
  4. Press Create key in the dialog. The key is shown once, at the top of the page. Only a hash of it is stored, so there is nothing to look up afterwards — copy it into wherever it is going to live before you leave the page.

Give every system its own key. One that leaks, or one whose supplier you stop using, can then be revoked on its own without stopping anything else. Revoking takes effect immediately and cannot be undone, so when you are replacing a key: create the new one, move over, then revoke the old one.

Calling it

The base URL is https://api.mapzaa.com. Every request carries its key in the Authorization header and every answer is JSON. Start with the index, which proves the key works and says which organisation it reaches:

curl https://api.mapzaa.com/v1 \
  -H "Authorization: Bearer mzk_…"

Anything that goes wrong comes back as {"error": {"code": "invalid_key", "message": "…"}}. Match on the code, which is stable; the message is English and is there for whoever is reading the log.

Reporting where something is

One asset at a time:

curl -X POST https://api.mapzaa.com/v1/assets/PLO-K3M9X2/location \
  -H "Authorization: Bearer mzk_…" \
  -H "Content-Type: application/json" \
  -d '{"lat": 63.8258, "lng": 20.2630}'

A whole fleet in one request, which is what a fleet should do — one call per tick for all of it, rather than one call per vehicle per tick:

curl -X POST https://api.mapzaa.com/v1/locations \
  -H "Authorization: Bearer mzk_…" \
  -H "Content-Type: application/json" \
  -d '{"updates": [
        {"code": "PLO-K3M9X2", "lat": 63.8261, "lng": 20.2554},
        {"code": "PLO-R7T2WD", "lat": 63.8190, "lng": 20.3011}
      ]}'

Entries are applied one at a time, so a single unknown code cannot throw away the nineteen good positions beside it. The answer says how many landed and names only the ones that did not: {"updated": 19, "failed": [{"asset": "PLO-XXXXXX", "error": "not_found"}]}.

Name an asset either by the code written on it or by the numeric id the API hands out. Only the second half of a code is matched, so PLO-K3M9X2 and K3M9X2 find the same thing — which means a code on a label keeps working after the asset is moved to another category and its prefix changes.

A report sets the coordinates and nothing else: not the category, not the status, and not the address, which is left exactly as you wrote it. An address is a fact about something that stands still, and re-deriving one for a moving vehicle every few seconds would produce a line that is wrong again before anybody reads it. Send "address" yourself if you do want it changed.

Around one report every ten seconds is a sensible interval: the map re-reads itself every fifteen, and a key may make 600 requests and report 6,000 positions a minute, a batch counting one per entry. That is a fleet of a thousand reporting every ten seconds through POST /v1/locations; past either limit the answer is 429 with the code rate_limited.

Seeing it move

Nothing has to be switched on. A position reported through the API lands in the same register the map draws, so the pin moves on its own, and the map refreshes every fifteen seconds for everyone who has it open. An asset that has reported in the last quarter of an hour is marked Live in the sidebar and on its pin, with the time it last said so — which is how you tell something that is reporting from something whose tracker has gone quiet.

Use the ordinary filters to watch one part of a fleet: a saved view of Category is Snow ploughs is a link you can leave open on a wall screen all night.

Reading the register

curl "https://api.mapzaa.com/v1/assets?category=Snow%20ploughs&moving=1" \
  -H "Authorization: Bearer mzk_…"

Filters are combined with AND, and the answer carries a total so you know how far there is to page.

ParameterWhat it does
statusactive, maintenance or retired.
categoryA category id or its name. none asks for the assets that have no category.
qMatches the address, the description and the code.
moving1 for the assets that have ever reported a position — the fleet, without having to know its codes.
moved_sinceOnly what has reported since this moment, as an RFC 3339 timestamp. This is the one a poll should use.
updated_sinceOnly what has changed at all since then, including edits made in the dashboard.
limit, offsetPage size (1–1000, 100 by default) and where to start.

There is also GET /v1/assets/{id or code} for a single asset, and GET /v1/categories for turning the names in a device's configuration into ids once rather than hard-coding a number somebody will later renumber.

Each asset comes back in the same shape — in the list as assets, beside total, limit and offset, and on its own as asset:

{
  "id": 1042,
  "ref": 57,
  "code": "PLO-K3M9X2",
  "category": {"id": 7, "name": "Snow ploughs", "color": "#2f6fed"},
  "status": "active",
  "location": {"lat": 63.8258, "lng": 20.263, "address": "Storgatan 12",
               "movedAt": "2026-01-14T06:12:09Z"},
  "description": "",
  "fields": {"registration": "ABC 123"},
  "createdAt": "2025-10-01T09:30:00Z",
  "updatedAt": "2026-01-14T06:12:09Z"
}

category is null for an asset without one, and location.movedAt is null until something has reported a position. fields holds your own asset fields, by each field's key.

What a key deliberately cannot do

A key cannot create an asset or delete one, change a category, a status or a custom field, reach another organisation's register, sign anybody in, or see your people. It reports a position and it reads. That is the whole of it.

This is a choice, not an omission. A key lives somewhere you do not control — a box in a cab, a server somebody else runs, a config file that outlives whoever wrote it — and the smallest thing it can be allowed to do is the right thing for it to do. For the same reason, position reports are the one change mapzaa does not write to the audit trail: a plough reporting every ten seconds from November to April would bury every entry a person ever made. Creating and revoking a key is recorded there, and when a key was last used is shown on the key itself.

Error codes

CodeStatusWhat it means
missing_key401No Authorization header.
invalid_key401The key is unknown or revoked.
read_only403A read-only key tried to report a position.
not_found404No asset with that id or code in your organisation.
unknown_endpoint404No such path under /v1.
bad_status, bad_category, bad_query, bad_timestamp, bad_limit, bad_offset400A filter value that cannot be used; the message says which and why.
bad_body, bad_location, bad_address, batch_too_large400A report that cannot be used: not JSON, coordinates missing or out of range, an address over 300 characters, or more than 500 positions in one batch.
rate_limited429Too many requests or positions in the last minute. Wait and send less often.
internal500Something went wrong on our side. Try again.

Something not covered here?

Email [email protected] — we usually reply the same day. If you are not set up yet, we will put your municipality on the map in about twenty minutes.

Book a free demo

Twenty minutes on a video call. We set up a register for your municipality, put a few of your real assets on it and show you around — no sales sequence afterwards.

We use these details only to reply to you. Privacy policy

Prefer email? Write to [email protected]

Start evaluating for free

We create your organisation and invite your first administrator, who then invites the rest of the team. Evaluating and testing mapzaa is free.

We use these details only to reply to you. Privacy policy

Prefer email? Write to [email protected]

Ask for a price

Tell us roughly what your register holds and who will use it, and we'll come back with a price that fits.

We use these details only to reply to you. Privacy policy

Prefer email? Write to [email protected]

Move your register to mapzaa

Tell us where your assets live today — a spreadsheet, a GIS export or another system — and we'll tell you how we would bring them across.

We use these details only to reply to you. Privacy policy

Prefer email? Write to [email protected]

Contact us

Questions about the product, pricing, security or data protection.

We use these details only to reply to you. Privacy policy

Prefer email? Write to [email protected]

Thanks — your message is on its way

We'll reply to the email address you gave, usually the same working day.

Close