Anleitungen

Single-use codes

Give each respondent a personal code for exactly one response, on a ticket, receipt or card, and create, print, check and revoke the codes over REST or MCP.

Die Entwickler-Dokumentation gibt es nur auf Englisch, wie die API selbst.

A survey in code mode can only be answered with a personal code, and each code allows exactly one response. You create the codes over the API and hand one to each person: in a link, as a QR code on a ticket or receipt, or printed on a card. Use it when every response should come from someone you invited, for example:

  • Events and trade fairs: the ticketing system adds a code to each ticket, so every attendee rates the event once.
  • Shops and repair services: the till prints a QR code with its own code on each receipt, so each purchase or repair can be rated once.
  • Courses and workshops: the trainer hands out one card per participant at the end of the day.
  • Employee surveys: HR gives each employee a code, so nobody answers twice and nobody from outside answers.
  • Hotels: the booking system sends a link with a code at checkout, so each stay is rated once.

Reading codes needs a key with access-codes:read; creating and revoking them needs access-codes:write. Neither scope can change a survey, so the key in a till or a ticketing system can mint codes without being able to rewrite your surveys. Switching a survey to code mode is a survey change and needs surveys:write. Code mode needs a plan that includes single-use codes; otherwise the calls answer 403 FEATURE_NOT_IN_TIER. The shell variables SF_API, SF_KEY and SURVEY_ID are set up as in the Quickstart.

Switch the survey to code mode

Code mode is settings.participation.accessMode: code lets only people with an unused code answer; open, or no value, lets anyone with the link answer. settings is replaced as a whole, so read it, change the one field and send it back:

bash
curl -s "$SF_API/v1/surveys/$SURVEY_ID" -H "Authorization: Bearer $SF_KEY" \
  | jq '{ settings: (.settings | .participation.accessMode = "code") }' \
  | curl -X PATCH "$SF_API/v1/surveys/$SURVEY_ID" \
      -H "Authorization: Bearer $SF_KEY" \
      -H "Content-Type: application/json" \
      -d @-

In code mode the code is the only rule against answering twice: participation.repeatParticipation, which limits each device, no longer applies, so two people sharing one phone can each answer with their own code. The start and end date and the maximum number of responses still apply. You can create codes before or after switching.

Switching back to open is always allowed and lets anyone with the link answer again. After a downgrade to a plan without single-use codes, a survey in code mode keeps asking for codes; it never opens up on its own. Its existing codes keep working and can still be listed and revoked, but no new ones can be created.

Create codes

bash
curl -X POST "$SF_API/v1/surveys/$SURVEY_ID/access-codes" \
  -H "Authorization: Bearer $SF_KEY" \
  -H "Idempotency-Key: 0b8f6a52-5d1e-4f0e-9a43-7c2d8e1b9f60" \
  -H "Content-Type: application/json" \
  -d '{ "count": 200, "label": "Trade fair, day 1", "includeImage": true }'

The answer is 201 with one entry per code:

json
{
  "data": [
    {
      "id": "cmvbatbky000bp57dddn3fp5i",
      "code": "8PJN4-GS8FX",
      "label": "Trade fair, day 1",
      "url": "https://simplefeedback.de/p/4c303674-1dd4-4836-ada7-0092fe2c7df3?code=8PJN4-GS8FX",
      "qrDataUrl": "data:image/png;base64,iVBORw0KGgo..."
    }
  ]
}
  • count is 1 to 500 per call. A survey holds at most 10 000 codes; a call that would go over answers 409 ACCESS_CODE_LIMIT_REACHED and creates none.
  • label is an optional note for the batch, up to 255 characters, shown when you list the codes. Don't put names of people in it; see Privacy.
  • includeImage: true adds qrDataUrl to every code: a 512 × 512 PNG of its url for printing, about 5 kB each.
  • A code is ten characters, printed as XXXXX-XXXXX, from digits and capital letters without I, L, O and U.

Send an Idempotency-Key so that a retry after a timeout returns the same codes instead of creating a second batch. A till that creates one code per receipt can use the receipt number as the key.

Hand them out

Every code reaches its respondent inside url, the survey link with the code in it. Opening it shows the survey with the code filled in; the code is checked when the survey opens and again when the response is sent.

Where How
Email, app, SMS Put url behind a button or link
Ticket, receipt Print the code's QR code: qrDataUrl, or a QR code of url from your own library
Cards, flyers Print one QR code per card

These QR codes are not saved QR codes: they don't count against your plan's QR code limit, don't appear in the dashboard's QR code list and their scans are not counted in QR code statistics.

To print a code again, send it back and get its link and QR code:

bash
curl -X POST "$SF_API/v1/surveys/$SURVEY_ID/access-codes/qr" \
  -H "Authorization: Bearer $SF_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "code": "8PJN4-GS8FX" }'

The answer is { "url": "…", "qrDataUrl": "data:image/png;base64,…" }. It changes nothing and is a POST only so the code stays out of URLs and access logs. Case, spaces and hyphens don't matter, and O, I and L are read as 0, 1 and 1. A code that is not one of this survey's answers 404 ACCESS_CODE_NOT_FOUND.

What respondents see

A respondent who opens the survey without a code, with an unknown or revoked code, or with a code that was already used is told so and can't answer. The same reasons come back from the public survey routes the survey page uses:

Code Status Meaning
ACCESS_CODE_REQUIRED 403 The survey is in code mode and no code came
ACCESS_CODE_INVALID 403 The code is unknown or revoked
ACCESS_CODE_USED 409 The code was already used for a response

Unknown and revoked codes give the same answer, so trying codes reveals nothing about them. A code is used only by a response that is accepted: a response refused for another reason, for example because the survey has ended, leaves the code unused. When two responses arrive with the same code at the same moment, exactly one is accepted.

Check which codes were used

bash
curl "$SF_API/v1/surveys/$SURVEY_ID/access-codes?status=used" \
  -H "Authorization: Bearer $SF_KEY"
json
{
  "data": [
    {
      "id": "cmvbatbky000bp57dddn3fp5i",
      "label": "Trade fair, day 1",
      "status": "used",
      "createdAt": "2026-10-16T18:25:54.658Z",
      "usedOn": "2026-10-16",
      "revokedAt": null
    }
  ],
  "pagination": { "total": 1, "limit": 25, "offset": 0 }
}

status is unused, used or revoked; filter by it with status, page with limit and offset as on every list. The codes themselves are never returned. usedOn is only the day, with no time. To count codes, ask for one status with limit=1 and read pagination.total.

Revoke the rest

When the event is over or a batch was printed by mistake, revoke the codes that are still unused:

bash
curl -X POST "$SF_API/v1/surveys/$SURVEY_ID/access-codes/revoke" \
  -H "Authorization: Bearer $SF_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "all": true }'

Send { "all": true } for every unused code, or { "ids": ["…"] } with up to 500 ids from the list; one of the two, or the call answers 400 VALIDATION_FAILED. The answer is { "revoked": 12 }, the number of codes revoked. Only unused codes are revoked; a used code stays used and its response stays. There is no undo.

Read the responses

Responses of a survey in code mode are read like any other, with GET /v1/surveys/{id}/responses and /statistics; see Syncing results. A response carries nothing about the code it was sent with.

Privacy

Simple Feedback stores no link between a response and its code: the response doesn't name the code, the code doesn't name the response, and usedOn is a day, not a time. Whether responses stay anonymous depends on how you hand the codes out:

  • Codes handed out without names (a stack of cards at the door, a code on every receipt) keep responses anonymous. Nobody can tell who had which code.
  • Codes given to named people (a list of who got which code, a label with a name, a link in a personal email that you keep) make responses pseudonymous at best. With few responses per day, the day a code was used can be enough to tell whose response is whose.

In the second case you process personal data: you need a legal basis for it and must tell respondents before they answer. Keep label for batches ("Trade fair, day 1", "Course B"), never for people. Deleting a survey deletes its codes with it.

Over MCP

An AI assistant does the same with four tools. Code mode is switched on with update_survey, which sends the whole settings like the PATCH above.

Tool Scope Over REST
create_access_codes access-codes:write POST /v1/surveys/{id}/access-codes
list_access_codes access-codes:read GET /v1/surveys/{id}/access-codes
revoke_access_codes access-codes:write POST /v1/surveys/{id}/access-codes/revoke
get_access_code_qr access-codes:read POST /v1/surveys/{id}/access-codes/qr

create_access_codes takes count and label but no includeImage: the codes and their links come back as text, and the tool tells the assistant to hand them to you at once, since they can't be read again. For a printable image of one code, the assistant calls get_access_code_qr with that code. revoke_access_codes is marked as destructive, so clients such as Claude ask before calling it. All four take an optional idempotencyKey.