Skip to main content
Workflows are automated message sequences you build in Blujay. A workflow that starts manually can be started for a contact from the API, so an event in your own system, such as a signup or a missed appointment, can put someone into a Blujay sequence. You find the workflows with GET /v1/workflows and enroll a contact with POST /v1/workflows/{workflow_id}/enrollments.

List workflows

GET /v1/workflows returns the active, published workflows in your workspace that start manually, oldest first, up to 100. Each has a workflow_id and a label. Workflows that start another way, such as when a tag is added, aren’t listed. The list isn’t paginated.
curl
Response (200)
Workflow steps and run history aren’t returned. Build and edit workflows in the Blujay app.

Enroll a contact

Send the contact’s ID and a request_id that identifies this enrollment in your system.
curl
Response (201)
A 201 means the contact was enrolled and a workflow run started. The workflow’s first step runs from Blujay’s queue after the response; the messages it sends show up as message.sent and later events on your webhooks, with no link back to the enrollment.

Response fields

Retry safely with request_id

request_id is required (1 to 200 characters) and is how this endpoint avoids double enrollments. It doesn’t use the Idempotency-Key header.
  • Sending the same request_id for the same workflow and contact again returns 200 with the original result. The contact isn’t enrolled twice.
  • The original result wins: a repeat with different metadata doesn’t change the enrollment.
  • The same request_id for a different contact is a separate enrollment.
  • A request that was rejected with an error isn’t remembered. After you fix the problem, send it again with the same request_id.
Use an ID that is stable for the event you’re reacting to, such as your signup ID or order ID, so a retry after a timeout reuses it. Use a new ID when you want to enroll the same contact again later. See Idempotency for how other endpoints handle retries.

Understand enrollments that don’t start a run

A 200 can also mean Blujay accepted the enrollment but didn’t start a new run. Check enrollment_status and no_op_reason:
Response (200)

Add metadata

metadata is optional context about the enrollment, such as where it came from. Blujay stores it on the enrollment record so the enrollment can be traced back to your system when you contact support. Workflow steps can’t read it, it doesn’t change what the workflow sends, and no endpoint or webhook returns it.
  • Up to 20 keys, each 1 to 64 characters.
  • Values are strings (up to 500 characters), numbers, booleans or null.
  • 4,096 bytes in total, measured as JSON.
Metadata over these limits returns 400 VALIDATION_ERROR.

Handle errors

Limitations

  • Enrollment is fire-and-forget. There is no endpoint to list a contact’s runs, read a run’s progress, cancel a run, or remove a contact from a workflow, and no webhook when a run starts, finishes or fails. Manage runs in the Blujay app.
  • Only workflows that start manually can be enrolled through the API. Tag-triggered workflows start when you add the tag.
  • One run per contact per workflow at a time: a second enrollment returns no_op with duplicate_non_terminal_run until the first run ends.
  • An opted-out contact is never enrolled (no_op, contact_opted_out).
  • The messages a workflow sends follow the same sending rules and plan limits as API sends. A run on a Free Plan or AI Agent number can only message people who texted that number first; see Plans.
  • metadata is write-only.

Next steps

Contacts

Create or find the contact to enroll.

Opt-outs

Understand why an opted-out contact isn’t enrolled.

Idempotency

See how retries work across the API.