ResponseDock Docs
Menu

Triggers API

Endpoints

GET/workspaces/:wid/triggersList triggers in a workspace
POST/workspaces/:wid/triggersCreate a trigger
PATCH/triggers/:idUpdate a trigger
DELETE/triggers/:idDelete a trigger
POST/workspaces/:wid/triggers/debugExplain how triggers evaluate an event
GET/workspaces/:wid/triggers/debug-historyLast 100 debug evaluations
POST/sdk/eventsTrack an event (SDK endpoint)

Managing triggers requires a workspace owner or admin. The list is ordered by priority (highest first), then newest first, and returned as { "triggers": [...] }. Creating, updating and deleting a trigger dispatches the trigger.created, trigger.updated and trigger.deleted webhooks.

Trigger Object

{
  "id":          "trig_xxxx",
  "workspaceId": "ws_xxxx",
  "surveyId":    "survey_yyyy",
  "eventName":   "match_completed",
  "conditions": [
    {
      "field":    "result",
      "operator": "equals",
      "value":    "win"
    }
  ],
  "priority":            1,
  "frequencyRule":       "ONCE_PER_CONTEXT",
  "contextKey":          "matchId",   // ONCE_PER_CONTEXT only
  "frequencyDays":       null,        // ONCE_PER_X_DAYS only; 30 when null
  "cooldownSeconds":     86400,       // 24 hours
  "maxDisplaysPerUser":  3,
  "maxResponsesPerUser": 1,
  "sampleRate":          1,
  "holdoutRate":         0,
  "environment":         "PRODUCTION",
  "isActive":            true,
  "startsAt":            null,
  "endsAt":              null,
  "createdAt":           "2026-10-01T09:00:00.000Z",
  "updatedAt":           "2026-10-01T09:00:00.000Z"
}

Fields

FieldTypeDescription
surveyIdstringRequired on create. Must belong to the same workspace
eventNamestringRequired on create. Event name the SDK sends, e.g. match_completed or $pageview
conditionsarray{ field, operator, value } rules; all must match. Default []
priorityintegerHigher is evaluated first. Default 0
frequencyRuleenumONCE_EVER, ONCE_PER_USER (default), ONCE_PER_CONTEXT, ONCE_PER_X_DAYS or UNLIMITED
contextKeystring | nullEvent property identifying the context for ONCE_PER_CONTEXT. Letters, numbers and _ . : -, up to 80 characters
frequencyDaysinteger | nullDays between displays for ONCE_PER_X_DAYS, 1 to 365. 30 when null
cooldownSecondsinteger | nullMinimum seconds between displays to the same person
maxDisplaysPerUserinteger | nullDisplay limit per person; null for no limit
maxResponsesPerUserinteger | nullCompleted-response limit per person; null for no limit
sampleRatenumber0 to 1. Share of eligible people who can see the survey. Default 1
holdoutRatenumber0 to 0.95. Share of people held out as a control group. Default 0
environmentenumPRODUCTION (default), STAGING or DEVELOPMENT
isActivebooleanDefault true
startsAt, endsAtISO datetime | nullOptional schedule window

Response-based rules (ONCE_EVER, ONCE_PER_USER, maxResponsesPerUser) count completed responses for identified users. Display-based rules (cooldownSeconds, ONCE_PER_CONTEXT, ONCE_PER_X_DAYS, maxDisplaysPerUser) count displays the server records. Anonymous visitors are capped by displays for every rule. See the trigger engine guide for the full semantics.

Create a Trigger

POST /workspaces/:wid/triggers

{
  "surveyId":        "survey_yyyy",
  "eventName":       "match_completed",
  "conditions": [
    { "field": "sport", "operator": "equals", "value": "football" }
  ],
  "frequencyRule":   "ONCE_PER_CONTEXT",
  "contextKey":      "matchId",
  "priority":        1,
  "cooldownSeconds": 3600,
  "isActive":        true
}

// 201 Created
{ "trigger": { ...trigger object } }

PATCH /triggers/:id accepts any subset of the same fields and returns { "trigger": ... }. DELETE /triggers/:id returns 204.

Debug an Event

POST /workspaces/:wid/triggers/debug

{
  "eventName":      "match_completed",
  "properties":     { "matchId": "match_789", "result": "win" },
  "externalUserId": "user_123",        // or "anonymousId": "anon_..."
  "environment":    "PRODUCTION"
}

// 200 OK
{
  "result": [
    {
      "triggerId":   "trig_xxxx",
      "surveyId":    "survey_yyyy",
      "surveyTitle": "Post-match feedback",
      "eventName":   "match_completed",
      "matched":     false,
      "reasons":     ["Survey was already shown for matchId = match_789."],
      "conditions":  [{ "field": "result", "operator": "equals", "expected": "win", "actual": "win", "passed": true, ... }]
    }
  ]
}

The debugger checks every trigger for the event and environment, including inactive ones, and stores the evaluation in the debug history. It never records a display.

Track an Event (SDK endpoint)

POST /sdk/events

// Headers:
// X-Project-Key: pk_live_xxxx

{
  "event": "match_completed",
  "properties": {
    "matchId": "match_789",
    "result":  "win"
  },
  "externalUserId": "user_123",       // identified user (optional)
  "anonymousId":    "anon_k3j9x...",  // persisted visitor id (optional, max 200 chars)
  "traits":  { "plan": "pro" },        // matched as trait.plan
  "context": { "page": "/dashboard" }, // matched as context.page
  "environment": "PRODUCTION"          // default PRODUCTION
}

// 200 OK — returns eligible surveys, highest priority first
{
  "surveys": [
    {
      "id":            "survey_yyyy",
      "slug":          "post-match-feedback",
      "workspaceSlug": "acme"
    }
  ]
}

anonymousId is a top-level field. When there is no externalUserId, sampling, holdouts and frequency caps apply per anonymousId. The browser SDK generates and sends it automatically. When at least one survey is returned, the server records a display of the first one for this user or visitor in the same request, so the caps hold even if the client never opens it.

Condition Operators

"equals" | "not_equals" | "contains" | "not_contains"
"greater_than" | "less_than"
"exists" | "not_exists"
"in_list" | "not_in_list"