Read a contact's enrolment decisions across every workflow
Every enrolment decision taken about one contact, across every drip
workflow, newest first — the contact-side view of the trace behind
GET /v1/workflows/{id}/enrollment-decisions.
Retained for 14 days. This is a debugging aid, not a record.
No reason_counts: the tally is only filled when the read is narrowed
to one workflow, because a count mixed across unrelated journeys answers
no question anybody asked.
The path segment is a contact id OR an email address. The id form
needs only api.workflows.view, the scope that governs the rows
returned. The email form additionally requires api.contacts.view,
because resolving an address or an external id to a contact is a
contacts read and a workflows-only token must not be able to use this
route to learn which addresses exist; without it the response is 403.
Percent-encode @ as %40. The rows themselves never carry an
address.
Path parameters
email string required The contact's UUID, its email address (percent-encoded), or your own external_id. The two non-id forms are a contacts read and additionally require api.contacts.view.
Query parameters
since string<date-time> optional RFC 3339. Clamped to the 14-day retention.
limit integer optional Responses
Errors follow the RFC 7807 problem format — see the error reference.
data array<object> required Each entry in data:
workflow_id string<uuid> required contact_id string<uuid> required cause string optional The trigger kind: segment, event, activity or date_rel.
source_key string optional The segment key, event name or activity name the signal fired on.
decision string enum required errored is the enrolment path failing rather than declining — a distinction worth keeping, because a contact missing for either reason looks identical from outside.
One of: enrolled, skipped, errored
reason string optional Which exit was taken. One of workflow_not_active,
trigger_stale, before_forward_floor,
reentry_once_already_ran, success_exit_still_matches,
entry_predicate_false, already_live_run,
outside_shadow_cohort, source_unparseable or
enroll_insert_failed. Absent on an enrolled decision, which has
no reason to give.
detail string optional Whatever makes the reason actionable — the predicate text, the forward floor and the event instant, the workflow's status.
run_id string<uuid> optional The run an enrolled decision produced. Absent on a skip.
shadow boolean required Whether the decision was taken while the workflow was shadowing.
occurred_at string<date-time> required reason_counts object optional The tally by reason over the same window. Present only when the read is narrowed to one workflow — a count mixed across every workflow a contact ever touched answers no question anybody asked.
validation_failed Problem. When the refusal is about a
reference — a segment key, template slug, topic or attribute name the
organization does not have — it additionally carries validation_code,
field, line/column, missing, candidates and next_step, so a
client can correct the call without a second round of guessing. See
ValidationProblem.
application/problem+json code is internal_error. The
request_id field can be quoted to SendOps support to investigate.
application/problem+json