Skip to main content
PATCH

Authorizations

next-auth.session-token
string
cookie
required

NextAuth session JWT cookie. Development: often next-auth.session-token. Production (HTTPS): often __Secure-next-auth.session-token. Send the cookie your browser receives after sign-in.

Path Parameters

responseId
string<cuid2>
required

Response identifier.

Body

application/json

Partially updates a response. Strict at the top level: unknown keys return 400 rather than being ignored, and at least one patchable field must be present.

data is replaced wholesale, not deep-merged — send the complete answer map you want stored. embeddedData is the exception and merges by name: it addresses individual fields, so a field the payload omits keeps its value rather than being cleared.

v3 replaces on purpose, where v1 and v2 merge: a merge makes it impossible to delete an answer, which a correction flow needs.

Every patch runs the response pipeline, emitting responseUpdated — so webhooks, integrations and follow-ups fire for a correction as much as for a substantive edit. A patch that transitions the response to finished additionally emits responseFinished; one that patches an already-finished response does not re-emit it.

Not patchable, and rejected if sent: createdAt, updatedAt, surveyId, contactId, displayId, singleUseId, contactAttributes, and the create-only ttc and meta — timing and submission context describe the original submission event, so they are set once and not revised. contactId is create-only deliberately — re-attributing an existing response to a different person is a capability only v2 offers, and it is not carried forward.

finished
boolean
endingId
string | null
language
string | null
data
object

The same map on the way in, with the cardinality bounds a v3 write enforces.

At most 500 keys, and at most 1000 entries in a multi-select array or matrix object. Both sit far above any real survey — a response holds one entry per element, a multi-select answer one per choice — and exist because every later reader pays per entry: the serializer's per-answer mapping, export columns, and the positional probe the "Other" response filter emits. Exceeding either is a 400 from the request schema, not a 422.

Deliberately separate from ResponseDataMap, which the read returns. These bounds are v3-only — the v1 and v2 write paths store the same map without them — so a stored response may exceed them, and the read schema must not claim otherwise.

embeddedData
object

Embedded Data values to write, keyed by field name.

This is the write counterpart of embeddedData[] on the read, and it is keyed the way an author names a field rather than the way storage addresses it. A hidden field is stored under its name but a variable is stored under its cuid, and that split is an implementation detail of the storage layout — the server resolves a name to its storage key through the survey's Embedded Data links, so a caller never sees a cuid and never has to know which kind it is writing.

Which kinds are writable:

  • ingested (hidden fields) — accepted, through the same ingest contract the SDK uses: the name must be declared on the survey, the value is coerced to the field's declared type, a locked field ignores the write, and the whole payload is bounded. A name the survey does not declare is a 422 rather than a silent drop — knowing whether a name is declared means loading the survey, and these operations route every failure that needs stored state to 422.

  • computed (variables) — accepted, because a management caller correcting a response needs to, and v1 and v2 both allow it today.

  • reserved — refused. Auto-captured context describes the submission environment, and a caller-supplied value would be fiction. The three exceptions are source, url and action, which ResponseMetaInput accepts for exactly the replay case.

Values follow their field's declared type. A field the payload omits is left as it is; this is a merge over named fields, not a replacement of the collection.

null clears a field. Omission and null therefore mean different things — leave it alone versus remove its value — which is the only reading that makes a merge-shaped map able to express deletion at all. A cleared field is then absent from embeddedData[] on the next read, exactly as one that was never written, and a field whose definition carries a defaultValue falls back to that default rather than disappearing.

An ambiguous name is refused. The read says key is unique per kind rather than across the collection, because a survey predating the reserved-name guard can hold a variable and a hidden field under one name. This map has no kind, so on such a survey a name cannot say which field it means — and guessing would write the caller's value into the wrong one. A name that matches more than one declared field is a 422 naming it, for the same reason as an undeclared one; rename one side on the survey to clear it. The set is finite, frozen and tracked, and nothing new can enter it.

Reserved names collide differently and are not ambiguous: reserved is not writable at all, so a name that matches both a declared field and a catalog entry resolves to the declared one.

At most 500 names. Every name that matches no declared field becomes its own invalid_params entry naming it, so without a cap a large body answers with a 422 several times its own size. Far above any real survey; a v3-only bound, as on data.

tags
string<cuid2>[]

Complete set of tag ids for this response, replacing whatever is currently applied. Repeats are allowed and collapse, because the set is applied as a set. Tags must already exist in the same workspace — create them via POST /api/v3/tags.

Maximum array length: 100

Response

Response updated successfully

data
object
required

A survey response in the detailed view, as returned by GET /api/v3/responses/{responseId} and by the write endpoints. Everything in ResponseListItem, plus the identity and provenance fields the list view omits.

It also carries data — the answers as stored, returned unchanged, so a client can read a response, edit an answer and send it straight back. Embedded Data is not echoed in stored form: the read's embeddedData[] and a request's embeddedData map already address the same fields by the same names, so a second raw map would only republish the storage layout. That is the property v1/v2 had for free by being symmetric, and the one OpenAPI 3.1.1 argues for directly: its "Validating readOnly and writeOnly" section notes that making clients strip fields before a write is "burdensome for clients, particularly when the JSON data is complex or deeply nested".

They are not the same view, and the differences are deliberate. A write accepts ingested and computed fields only: a reserved entry describes the submission environment, and being able to read one back is not a licence to author it. An unset field is omitted from the read while null on a write clears one, because a merge-shaped map has no other way to spell deletion. And a name the read returns twice under different kinds cannot be written at all — see ResponseEmbeddedDataInput, which refuses an ambiguous name rather than guessing.

Values themselves round-trip: within those two kinds every value the read emits is accepted verbatim on a write, and a date reads and writes as the same ISO-8601 string. So a read-edit-write cycle loses nothing except in two cases, both confined to rows v1 or v2 wrote. The first is the finite set of legacy surveys carrying one name as both a variable and a hidden field, where the write refuses the name outright. The second is a data map holding more keys than ResponseDataMapInput accepts: the stored map is unbounded and the write bound is not, so such a response cannot be patched here — and trimming it to fit is not a workaround, since data is replaced wholesale and an omitted key is a deletion.

Note which fields carry readOnly here and which do not, because it is the opposite of what an "echo" framing would suggest. readOnly means a value is managed exclusively by the server, so it marks the derived views — answers[], embeddedData[], unresolved[], resolution, the denormalized surveyName and workspaceId, the timestamps, durationSeconds and id. data is not read-only: it is exactly what the write endpoints accept, and leaving it unmarked is what makes this representation round-trippable rather than merely informative.

To correct one answer, read this resource, take data, change the entry you want and PATCH { "data": … }. Send only the fields you are changing — PATCH rejects unknown and non-patchable keys, so passing the whole representation back verbatim is not the intended flow; passing data back is.

Never exposed on this resource, in either view: the respondent's IP address, and the contactAttributes snapshot that v1/v2 return. That snapshot is copied from the contact at submission time and never updated after, so it is stale PII by construction — contact covers the legitimate need to know who answered.