Welcome to Encatch Docs
Admin API ReferenceResponses

Submit Response

Store a form response from your backend with POST /v2/admin/forms/{formId}/responses, using the Standard body.

Validate a response against the form's live version, and store it if it passes. The response appears in Results within seconds. It also reaches your reports and destinations like a response from any other channel.

Turn on Distribution → API for the form first (see Response Submit API). Authenticate with an admin API key. Admin API rate limits apply.

POSThttps://api.encatch.com/engage-product/encatch/api/v2/admin/forms/%7BformId%7D/responses

To check a body without storing it, send the same body to Validate Response.

Authentication

X-Api-KeystringRequired

Admin (secret) API key. A sender that cannot set headers can pass it as the X-Api-Key query parameter instead; see Authentication.

Content-TypestringRequired

Request body format

application/json
Idempotency-Keystring

1 to 255 characters, unique per response. A repeat within 1 hour returns the first call's responseId with Idempotent-Replayed: true. A repeat with a different body gets 422, and a repeat while the first call is still queuing gets 409. See Idempotency and retries.

Publishable SDK keys receive 403 (publishable API keys cannot call /v2/admin routes).

Server-side only

Keep admin API keys on your server. Never ship them in client code.

Path parameters

formIdstringRequired

The form's UUID. Copy it from Distribution → API → API overview → Form ID.

Request body

Maximum body size: 100 KB (413 if larger). Only status and answers are required. Any top-level field not listed here returns 400 unsupported_field.

statusstringRequired

partial only means the response is not complete. A response is never updated later.

completedpartial
answersobjectRequired

Answers keyed by question slug or question UUID. The value shape depends on the question type; see Answer formats. To skip a question, leave it out or send null. Required questions are not enforced. Answering the same question by both slug and UUID returns duplicate_answer.

formIdstring

Optional. Must match the formId in the path.

externalIdstring

Your own id for this response or event, 1 to 255 characters. It works like Idempotency-Key: a repeat within 1 hour returns the same responseId, and a different body gets 422 idempotency_conflict.

submittedAtstring

When the response was given: ISO 8601 with a time zone, for example 2026-10-19T07:06:00Z. It can be up to 15 days in the past and no more than 2 minutes in the future. Defaults to now.

languagestring

One of the form's languages, for example en. Defaults to the form's default language.

userobject

The respondent. Leave it out for an anonymous response.

userNamestringRequired

An identified user that already exists; create one with Identify User. The contact variables the form uses are filled from this user's traits, as they are with the SDK. Contact values themselves cannot be sent.

contextobject

Values for the form's context variables, keyed by variable name.

sourceTrackingobject

Values for the form's source tracking parameters. A key that is not one of the form's parameters, or any key while source tracking is off, returns unknown_source_tracking_param.

deviceobject

Optional device metadata. Every key is a string or null. Unknown keys return unsupported_field.

Show 14 properties
timezonestring

IANA time zone, for example Europe/London

deviceOsstring

Operating system

deviceOsVersionstring

Operating system version

appstring

Application identifier

appVersionstring

Application version

deviceLanguagestring

Device locale, for example en-GB

userLanguagestring

User language, for example en

urlOrScreenNamestring

URL or screen name the response came from

deviceTypestring

Device type, for example desktop

deviceSizestring

Viewport class

preferredThemestring

Color scheme

browserstring

Browser name

browserVersionstring

Browser version

countryCodestring

ISO 3166-1 alpha-2 country code, for example GB

ipAddressstring

The respondent's IPv4 or IPv6 address.

completionTimeInSecondsnumber

Whole seconds the respondent took, from 0 to 2147483647.

timeSpentMsobject

Milliseconds spent on each question, keyed like answers (by slug or UUID). This field never rejects the request. Decimals are rounded to whole milliseconds, text that holds a number is read as that number, and values over 24 hours (86,400,000) are capped at 24 hours. 0, negative numbers, and anything else record no time.

Keys that are not a question, or that point to an unanswered question, are ignored, so a mistyped key loses its time without an error. When one question is given by both slug and UUID, the UUID entry is used.

aiEnrichmentboolean

AI topics for text answers, on completed responses only. Defaults to true.

Examples

cURL
curl -X POST 'https://api.encatch.com/engage-product/encatch/api/v2/admin/forms/3f8a2c1e-7b4d-4e9a-9c61-2d5f8e0b7a14/responses' \
  -H 'X-Api-Key: YOUR_ADMIN_API_KEY' \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "status": "completed",
    "externalId": "order-48213",
    "answers": {
      "how-likely-are-you-to-recommend-us": 9,
      "what-did-you-like-most": ["fast-delivery", "easy-checkout"],
      "anything-we-could-improve": "Tracking updates could be more frequent."
    }
  }'
JSONEvery optional field
{
  "status": "completed",
  "externalId": "order-48213",
  "submittedAt": "2026-10-19T07:06:00Z",
  "language": "en",
  "user": { "userName": "jane.doe@example.com" },
  "context": { "accountTier": "pro" },
  "device": {
    "timezone": "Europe/London",
    "deviceType": "desktop",
    "deviceOs": "macOS",
    "browser": "Chrome",
    "deviceLanguage": "en-GB",
    "countryCode": "GB"
  },
  "ipAddress": "203.0.113.7",
  "completionTimeInSeconds": 95,
  "aiEnrichment": true,
  "answers": {
    "how-likely-are-you-to-recommend-us": 9,
    "what-did-you-like-most": {
      "values": ["fast-delivery", "$Other"],
      "otherText": "The packaging"
    },
    "anything-we-could-improve": "Tracking updates could be more frequent."
  },
  "timeSpentMs": {
    "how-likely-are-you-to-recommend-us": 4200,
    "what-did-you-like-most": 12500,
    "anything-we-could-improve": 31000
  }
}

The example keys (how-likely-are-you-to-recommend-us and so on) are question slugs. Take the real slugs, UUIDs, and option values from Distribution → API → View questions or from the form's OpenAPI document.

Success response

202JSONResponse
{
  "responseId": "7d0f3b52-9a1e-4c8d-b6f2-5e4a3c2b1d09",
  "requestId": "4b1e0c7a92f3d811"
}
responseIdstringRequired

UUID of the stored response. A replayed request returns the first call's responseId.

requestIdstring

Correlation id for this call. Quote it when contacting support.

202 Accepted means the response is queued. It shows in Results within seconds. When the call answers a repeat (same Idempotency-Key or externalId, same body), the response carries the header Idempotent-Replayed: true and nothing new is stored.

Errors

Failed calls return application/problem+json (RFC 9457) with a stable code. When the body has more than one problem, code is validation_failed, and every problem is listed in invalidParams with its own code. Match on code, not on detail or message. Treat a code you do not know like any other error with that status. The full list is on Error codes.

422Error
{
  "type": "about:blank",
  "title": "Unprocessable Entity",
  "status": 422,
  "code": "out_of_range",
  "detail": "Must be between 0 and 10.",
  "requestId": "4b1e0c7a92f3d811",
  "invalidParams": [
    {
      "name": "answers.how-likely-are-you-to-recommend-us",
      "code": "out_of_range",
      "message": "Must be between 0 and 10."
    }
  ]
}
StatusWhen
400Body is not valid JSON or a field has the wrong type (malformed_body), unknown top-level field (unsupported_field), formId in the body differs from the path (form_id_mismatch), or Idempotency-Key is not 1 to 255 characters (invalid_idempotency_key)
401Missing or unknown API key; answered by the gateway as { "error": "..." }, without a code
403The key is a publishable SDK key, not an admin key; answered by the gateway, without a code
404No form with this formId in the key's project (form_not_found)
409The first request with this Idempotency-Key or externalId is still being queued (request_in_progress); retry after Retry-After seconds
413Body larger than 100 KB (body_too_large)
422The form cannot take a response now (form_not_live, api_channel_disabled, outside_schedule, response_limit_reached, usage_quota_exceeded), the body has problems (see Error codes), or the same key was used in the last hour with a different body (idempotency_conflict)
429Admin API rate limit reached
503The queue or file storage is temporarily unavailable (temporarily_unavailable); safe to retry with the same Idempotency-Key
401Gateway errors
{
  "error": "api key is required"
}

Was this page helpful?