REST API
Work with your projects, folders, products and members from your own software, try requests from the Developer page, and receive webhooks when things happen.
The REST API lets your own software read and change what is in your Measure Map Online account: projects and their measurements, folders, the product catalogue and, on Enterprise, the members of your organisation. It answers in JSON. The full reference, with every field and example, is the API documentation; this page is the overview.
To open the documentation from the app, go to Developer > REST API and press View documentation.
Base URL#
Every request goes to:
https://api.measuremaponline.com/api/v2
Authentication#
Send your API key, as it is, in the Authorization header of every request.
Create the key on the Developer page: see API keys.
curl https://api.measuremaponline.com/api/v2/projects/YOUR_PROJECT_ID \
-H "Authorization: YOUR_API_KEY"
Each request is checked against the key's access (for example, Projects Read), your subscription and, for a request sent from a web page, the key's website restrictions. Keep keys that can change data on your server: see keep your key safe.
Live and sandbox#
There is one base URL for both. The key decides: a sandbox key reads and writes sandbox projects, folders and products, which live keys never see. Members are the same in both, but signing in as a member needs a live key. Guest projects made with a sandbox key are never billed, and sandbox projects cannot be embedded on your website. Tokens report the environment they belong to.
What the API covers#
| Group | Endpoints | Key access needed |
|---|---|---|
| Sign-in tokens | POST /auth/token, POST /auth/iframe/token |
Embedded maps |
| Projects and folders | List a person's projects (all, or page by page, up to 200 a page) and folders; get a project, its measurements (/projects/{pid}/data), its comments, or its .mmp file (/projects/{pid}/mmp); get a folder; create, update and delete projects and folders |
Projects: Read to read, Read & change to change |
| Products | GET /products, GET /products/{id}, create, update, and archive with DELETE /products/{id} |
Products: Read or Read & change |
| Members (Enterprise) | GET /users, GET /users/{uid}, POST /users/new, PUT /users/{uid}, DELETE /users/{uid} |
Users: Read or Read & change |
| Signing in as a member (Enterprise) | POST /auth/{uid}/login gives a sign-in token for a member of your organisation |
Users: Read & change |
A few things to know:
- A key reaches the projects of its own account and, on Enterprise, those of the organisation's members.
- Deleting a project or a folder through the API is permanent: nothing goes to the Trash. A folder takes with it the folders and projects inside that belong to your account or your members.
- In a project's measurements, a shape lists its products in
productIds, in order;productIdis the first of them. /projects/{pid}/mmpgives the same.mmpfile the app exports. Its schema is published at github.com/blueblinkone/mmp-validator. New elements are only ever added as optional ones, so a reader written for an older file keeps working.- On Open Guest, a project created through the API with the Open Guest access level counts towards your Open Guest usage and budget, like one started from your guest link.
- On Open Guest, the Guest link section has
the Open Guest API guide, with code for your server and your page:
your server gets a token from
POST /auth/tokenwith your live key and sends the visitor to a new project of their own, their details filled in. - Creating a member with
POST /users/newuses a seat, as an invitation does, and gives them your organisation's default role. - A token from
POST /auth/{uid}/loginopens that member's account, so it needs a key that may change members, never the key in your embeds. It is not given for an Admin or a Manager, nor with a sandbox key. - Products are never deleted through the API, only archived, and a product's cost price is never returned.
- Cadastral parcels are not part of the API.
Responses and errors#
A successful request answers with status 200 and JSON (the .mmp export
answers with XML). A failed one answers with an error status and a body such
as:
{"errorCode": "insufficient_scope", "errorMessage": "This API key does not have the scope required for this endpoint"}
| Status | errorCode |
What to check |
|---|---|---|
| 400 | invalid_body, invalid_uid, invalid_project_id, pagination_invalid_page_number, pagination_invalid_page_limit |
A value in the request is missing or not accepted, such as the page and limit of a paged list. |
| 401 | unauthorized_action |
The request was sent from a web page on a website the key does not allow, or the item is not on your account or your members'. |
| 402 | budget_limit_reached |
Open Guest: your budget limit is reached, so no more guest projects this period. |
| 403 | invalid_api_key |
No key was sent in the Authorization header, or the key is unknown, revoked, or past its 24 hours after being replaced. |
| 403 | api_key_suspended |
API access on your account has been suspended. Contact support. |
| 403 | subscription_expired, invalid_subscription |
The subscription is not active, or its plan has no API. |
| 403 | insufficient_scope |
The key does not have the access this endpoint needs. |
| 403 | scope_not_in_plan |
Your plan does not include this endpoint, for example members on Open Guest. |
| 404 | not_found, project_not_found, user_not_found |
The item does not exist, or the person is not a member of your organisation. |
| 409 | enterprise_add_users_limit |
Creating a member: every seat is taken. |
| 429 | too_many_requests |
More than 600 tokens in an hour. Wait a little and try again. |
| 500 | server_error |
The request could not be completed. Check the IDs you sent, try again, and contact support if it persists. |
Try the API from the Developer page#
Developer > Try the API sends real requests with your key and shows exactly what comes back.
- Choose Live or Sandbox.
- Pick an Endpoint, such as "List all projects" or "Get measurements".
- Fill in its parameters. A project or a product is picked by name from those the key can read; where a person is needed, your own account is filled in for you.
- Press Send request. The status and the response appear below.
Only requests that read are offered, so nothing is changed by trying, and these requests are not counted in your usage. If your key does not have the access an endpoint needs, the page warns you that it will answer 403.
Webhooks#
A webhook tells your server when something happens, as the notification emails tell you. Webhooks are part of the Enterprise and Open Guest plans.
Set up a webhook#
In Developer > Webhooks:
- Type your Endpoint URL: an
https://address on the internet. Addresses on private networks are refused, and this is checked again before every delivery. - Tick the Events you want (see events). A new endpoint starts with the events your plan sends, and at least one must be ticked.
- Press Save. The first time, the page shows your Signing secret in full. Copy it then: afterwards only its last characters are shown.
- Press Send test event and pick an event.
A test sends a sample of that event, with made-up values and "test": true
in its data, to your saved endpoint, even when the event is not ticked or
the endpoint is switched off. To stop all deliveries, press
Remove: the endpoint and its secret
are deleted.
Below the settings, the Webhook reference has what you need to write the receiving end: the headers and the body, code that checks the signature in Node.js, Python and PHP, and example data for every event.
What your server receives#
Each event is one POST to your endpoint, with a JSON body:
{"id": "evt_3f9a1c2b7d4e5f60718293a4", "type": "project.created", "created": 1790000000000, "data": { ... }}
id is unique for each event, created is when it happened in milliseconds
since 1 January 1970 (UTC), and what data holds depends on the event. The
request also has these headers:
| Header | Value |
|---|---|
X-MMO-Event |
The event name, as type in the body. |
X-MMO-Delivery |
The event's id. |
X-MMO-Signature |
t=<milliseconds>,v1=<hex>: when the delivery was signed, and its signature. |
User-Agent |
MeasureMapOnline-Webhooks/1 |
- Answer with a 2xx status within 8 seconds, before any slow work. Any other status, a redirect or a timeout counts as a failure.
- Each event is sent once and never retried. The section shows the Last delivery and the Consecutive failures.
- After 10 failures in a row, the endpoint is switched off and the owner gets an email. Fix your server and press Save to switch it back on.
- Now and then an event arrives twice or out of order. Use
idto ignore repeats andcreatedto put events in order.
Check the signature#
Anyone who knows your address can post to it, so check every delivery before you trust it:
- Split the
X-MMO-Signatureheader at the comma intotandv1. - Compute an HMAC-SHA256 of
t, a full stop and the raw request body, with your signing secret as the key, written as hexadecimal. - Compare the result with
v1using a constant-time comparison. - Reject the delivery if
tis more than 5 minutes from the current time.tis in milliseconds.
Use the body exactly as it arrived: parsing the JSON and writing it out again changes it, and the signature no longer matches.
Rotate secret replaces the secret at once and shows the new one in full, once. Update your server as soon as you rotate.
Events#
| Event | Sent when |
|---|---|
project.created |
A project is created on your account. In the app, through the API or from an embed. |
project.deleted |
A project is permanently deleted (moving one to the trash does not count). |
project.comment.added |
Someone comments on a project — usually your client replying. |
guest.project.created (Open Guest) |
A guest starts a project from your link or through the API. Only when the guest's email address is known. |
guest.measurement.completed (Open Guest) |
A guest finishes a measurement and leaves their contact details. |
budget.warning_reached (Open Guest) |
Metered spend crosses your warning threshold. |
budget.limit_reached (Open Guest) |
Metered spend hits your limit — further guest projects are refused. |
enterprise.user.created (Enterprise) |
A seat is added to your organization, including through single sign-on. |
Still need help?
Write to our support team and tell us what you were trying to do. Screenshots help.