Use the REST API
The REST API does over HTTP what you do in the editor: create a survey, add sections and questions, publish it, and read or export its responses. Use it from a script, a reporting pipeline, a QGIS workflow or your own app.
The API is a Pro feature. Calls on a survey need the workspace that owns it to be on Pro;
anywhere else they answer pro_required. See Plans and billing.
Every endpoint and field is listed in the REST API reference.
Before you start
Section titled “Before you start”- Create a personal access token for the REST API. Leave publish and delete off unless your tool must do those.
- Keep the token in an environment variable, not in your code:
export MAPSURVEY_TOKEN=msk_…Your first calls
Section titled “Your first calls”Check what the token reaches — your workspaces, their plans and whether the API is available:
curl -H "Authorization: Bearer $MAPSURVEY_TOKEN" https://mapsurvey.org/api/v1/meCreate a survey, add a question to its first section and publish it:
API=https://mapsurvey.org/api/v1AUTH="Authorization: Bearer $MAPSURVEY_TOKEN"
# 1. A new survey (name the workspace by its slug if you belong to several)curl -s -X POST $API/surveys -H "$AUTH" -H "Content-Type: application/json" \ -d '{"name": "Park improvements", "workspace": "my-team"}'# → {"uuid": "…", "sections": [123], "status": "draft", …}
# 2. A point question in section 123curl -s -X POST $API/surveys/<uuid>/sections/123/questions -H "$AUTH" -H "Content-Type: application/json" \ -d '{"name": "Where would you add a bench?", "input_type": "point", "required": true}'
# 3. Publish (needs the surveys:publish permission)curl -s -X POST $API/surveys/<uuid>/publish -H "$AUTH" -H "Content-Type: application/json" -d '{}'# → {"status": "published", "review": null, "url": "https://mapsurvey.org/surveys/<uuid>/"}The same in Python, reading responses page by page:
import os, requests
API = "https://mapsurvey.org/api/v1"session = requests.Session()session.headers["Authorization"] = f"Bearer {os.environ['MAPSURVEY_TOKEN']}"
def responses(survey_uuid): cursor = None while True: page = session.get(f"{API}/surveys/{survey_uuid}/responses", params={"limit": 200, "cursor": cursor}).json() yield from page["items"] cursor = page["next_cursor"] if not cursor: break
for r in responses("<uuid>"): print(r["number"], [a["question"] for a in r["answers"]])Editing a live survey
Section titled “Editing a live survey”A published survey takes wording changes in place — question names, help text, translations,
new options — exactly as in the editor. A change of structure — adding, deleting or
reordering sections and questions, changing a question’s type, removing an option people have
already chosen, a visibility rule — is refused with 409 draft_required, because it would change
the survey under people who are answering it.
Make those changes on unpublished changes, then publish them:
curl -s -X POST $API/surveys/<uuid>/draft -H "$AUTH" # → {"uuid": "<draft uuid>", …}# … edit <draft uuid> like any draft survey …curl -s -X POST $API/surveys/<uuid>/draft/publish -H "$AUTH" -H "Content-Type: application/json" -d '{}'Respondents keep the live survey until you publish. See Edit a published survey for what counts as structure.
Errors
Section titled “Errors”Every error is {"error": "<code>", "detail": "<text>"}. Branch on error, never on detail.
The ones you will meet first:
pro_required— the survey’s workspace is not on Pro;upgrade_urlis its billing page.scope_missing— the token lacks a permission; create one that has it.validation—fieldssays which field is wrong and why. A field the API does not know is refused by name, so a typo never passes silently.answers_at_risk— a delete would remove answers; repeat it withacknowledge_answer_loss=trueonce you mean it.rate_limited— wait theRetry-Afterseconds.
The full list is in the reference.
Exporting data
Section titled “Exporting data”GET /surveys/<uuid>/export?format=gpkg returns the same file as Export data on the
Responses page: zip (GeoJSON + CSV), xlsx, csv, gpkg, shp or kml; add files=true
for uploaded photos and documents. See Export responses for what each
format contains.
A note for QGIS
Section titled “A note for QGIS”The quickest route into QGIS is the GeoPackage export: download
/surveys/<uuid>/export?format=gpkg with your token (a Python console snippet, or Layer → Add
Layer → Add Vector Layer after downloading) and open it — one layer per map question, with the
sub-question answers as attributes. Reference layers come from
/surveys/<uuid>/layers/<id>/geojson.
Limits
Section titled “Limits”600 reads and 60 writes a minute per token, 5 000 calls a day, and daily caps on creating (50) and deleting (20) surveys, importing (20) and exporting (100). The API sends no cookies and answers any origin, so a browser app can call it directly — keep the token out of public pages.
Was this page helpful?
Thanks — this helps us fix the page.
Still stuck? Contact support — we reply within a day, by email if you have left the page.