Skip to content

Start a run

POST
/workflows/{workflowId}/runs
curl --request POST \
--url https://api.usesonora.com/v1/workflows/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/runs \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "account": { "id": "example", "idType": "sonora" }, "recipients": { "roles": [ "example" ], "emails": [ "hello@example.com" ], "contactIds": [ "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0" ] }, "variables": { "additionalProperty": "example" } }'

Start the workflow for one account, or — with a JSON array body — for up to 100 accounts at once (207, one result per element, each what that account’s own call would have answered). The progress of a run is GET /workflow-runs/{runId}, under workflows:read.

Requires the workflows:trigger scope. API keys only.

workflowId
required
string format: uuid

The workflow’s chain root id (GET /workflows); a version id is 404.

Idempotency-Key
string
>= 1 characters <= 255 characters

1–255 printable characters. A retry with the same key and request answers with the first call’s result instead of acting twice.

Media typeapplication/json
Any of:

Start one run of an API-triggered workflow.

object
account
required

The account the run is about.

object
id
required

The account’s id, in the system idType names.

string
>= 1 characters <= 255 characters
idType

How id names the account: sonora (the default; Sonora’s customer id), salesforce, hubspot, domain, or custom_field:<key>.

string
default: sonora /^(sonora|salesforce|hubspot|domain|custom_field:[^\s].{0,99})$/
recipients

Who the run emails, for a workflow whose email steps send to people the call names. Required there, refused elsewhere.

object
roles

Contact role slugs (GET /contact-roles); everyone at the account in one of them.

Array<string>
<= 50 items
emails
Array<string>
<= 50 items
contactIds
Array<string>
<= 50 items
variables

Values for the workflow’s declared variables (GET /workflows): strings, numbers or booleans.

object
key
additional properties

An idempotent replay: the body the original call got.

Media typeapplication/json

What a start call started: the run’s fields fixed at acceptance. Its progress is GET links.self.

object
id
required
string
origin
required
string
Allowed values: auto manual api
workflow
required
object
id
required

The workflow’s chain root id.

string
versionId
required

The version the run executes.

string
name
required
string | null
account
required
Any of:
object
id
required
string
name
required
string | null
recipients
required

Who an API call named and the run reaches; empty otherwise.

Array<object>

One person an API call named that the run reaches.

object
contactId
required
string | null
email
required
string
name
required

Read fresh from the contact.

string | null
matchedBy
required
Array
One of:
object
type
required
string
Allowed value: role
role
required
string
createdAt
required
string format: date-time
links
required
object
self
required

This resource’s canonical URL on the API host.

string
trigger
required

What the API call that started a run asked for, and who it skipped.

object
requestId
required
string
receivedAt
required
string format: date-time
account
required
object
id
required
string
idType
required
string
roles
required

The roles the call matched, as slugs.

Array<string>
variables
required
object
key
additional properties
string | number | boolean
idempotencyKey
required
string | null
skippedRecipients
required
Array<object>

A person the call named who won’t be emailed.

object
contactId
string
email
string
reason
required
string
Allowed values: unsubscribed bounced do_not_contact no_email recently_triggered
matchedBy
required
Array
One of:
object
type
required
string
Allowed value: role
role
required
string
lastRunId

recently_triggered only: the run that last reached them through this workflow.

string
retryAfter

recently_triggered only: when the resend window lets a call reach them again.

string
Example
{
"origin": "auto",
"recipients": [
{
"matchedBy": [
{
"type": "role"
}
]
}
],
"trigger": {
"skippedRecipients": [
{
"reason": "unsubscribed",
"matchedBy": [
{
"type": "role"
}
]
}
]
}
}

The run started.

Media typeapplication/json

What a start call started: the run’s fields fixed at acceptance. Its progress is GET links.self.

object
id
required
string
origin
required
string
Allowed values: auto manual api
workflow
required
object
id
required

The workflow’s chain root id.

string
versionId
required

The version the run executes.

string
name
required
string | null
account
required
Any of:
object
id
required
string
name
required
string | null
recipients
required

Who an API call named and the run reaches; empty otherwise.

Array<object>

One person an API call named that the run reaches.

object
contactId
required
string | null
email
required
string
name
required

Read fresh from the contact.

string | null
matchedBy
required
Array
One of:
object
type
required
string
Allowed value: role
role
required
string
createdAt
required
string format: date-time
links
required
object
self
required

This resource’s canonical URL on the API host.

string
trigger
required

What the API call that started a run asked for, and who it skipped.

object
requestId
required
string
receivedAt
required
string format: date-time
account
required
object
id
required
string
idType
required
string
roles
required

The roles the call matched, as slugs.

Array<string>
variables
required
object
key
additional properties
string | number | boolean
idempotencyKey
required
string | null
skippedRecipients
required
Array<object>

A person the call named who won’t be emailed.

object
contactId
string
email
string
reason
required
string
Allowed values: unsubscribed bounced do_not_contact no_email recently_triggered
matchedBy
required
Array
One of:
object
type
required
string
Allowed value: role
role
required
string
lastRunId

recently_triggered only: the run that last reached them through this workflow.

string
retryAfter

recently_triggered only: when the resend window lets a call reach them again.

string
Example
{
"origin": "auto",
"recipients": [
{
"matchedBy": [
{
"type": "role"
}
]
}
],
"trigger": {
"skippedRecipients": [
{
"reason": "unsubscribed",
"matchedBy": [
{
"type": "role"
}
]
}
]
}
}

A batch: one result per element, in order.

Media typeapplication/json
object
data
required

One result per element, in order.

Array<object>

One element’s outcome.

object
status
required

What the single call for this element would have answered.

integer
body
required
Any of:

What a start call started: the run’s fields fixed at acceptance. Its progress is GET links.self.

object
id
required
string
origin
required
string
Allowed values: auto manual api
workflow
required
object
id
required

The workflow’s chain root id.

string
versionId
required

The version the run executes.

string
name
required
string | null
account
required
Any of:
object
id
required
string
name
required
string | null
recipients
required

Who an API call named and the run reaches; empty otherwise.

Array<object>

One person an API call named that the run reaches.

object
contactId
required
string | null
email
required
string
name
required

Read fresh from the contact.

string | null
matchedBy
required
Array
One of:
object
type
required
string
Allowed value: role
role
required
string
createdAt
required
string format: date-time
links
required
object
self
required

This resource’s canonical URL on the API host.

string
trigger
required

What the API call that started a run asked for, and who it skipped.

object
requestId
required
string
receivedAt
required
string format: date-time
account
required
object
id
required
string
idType
required
string
roles
required

The roles the call matched, as slugs.

Array<string>
variables
required
object
key
additional properties
string | number | boolean
idempotencyKey
required
string | null
skippedRecipients
required
Array<object>

A person the call named who won’t be emailed.

object
contactId
string
email
string
reason
required
string
Allowed values: unsubscribed bounced do_not_contact no_email recently_triggered
matchedBy
required
Array
One of:
object
type
required
string
Allowed value: role
role
required
string
lastRunId

recently_triggered only: the run that last reached them through this workflow.

string
retryAfter

recently_triggered only: when the resend window lets a call reach them again.

string
Example
{
"data": [
{
"body": {
"origin": "auto",
"recipients": [
{
"matchedBy": [
{
"type": "role"
}
]
}
],
"trigger": {
"skippedRecipients": [
{
"reason": "unsubscribed",
"matchedBy": [
{
"type": "role"
}
]
}
]
}
}
}
]
}

invalid_json: The request body is not valid JSON.

invalid_request: A parameter or body field is missing, malformed or unknown; details.issues names each.

Media typeapplication/json

The one error shape every endpoint answers with.

object
error
required
object
code
required

Stable snake_case code to branch on; see the error table.

string
message
required

For humans; may change.

string
details
object
key
additional properties
requestId
required

Quote it when asking for help.

string | null
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {
"additionalProperty": "example"
},
"requestId": "example"
}
}

unauthorized: The Authorization header is missing, or the key is invalid, revoked or expired.

Media typeapplication/json

The one error shape every endpoint answers with.

object
error
required
object
code
required

Stable snake_case code to branch on; see the error table.

string
message
required

For humans; may change.

string
details
object
key
additional properties
requestId
required

Quote it when asking for help.

string | null
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {
"additionalProperty": "example"
},
"requestId": "example"
}
}

insufficient_scope: The key or token lacks the scope this endpoint needs, and details.required names it; or an OAuth access token called an endpoint only an API key can.

Media typeapplication/json

The one error shape every endpoint answers with.

object
error
required
object
code
required

Stable snake_case code to branch on; see the error table.

string
message
required

For humans; may change.

string
details
object
key
additional properties
requestId
required

Quote it when asking for help.

string | null
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {
"additionalProperty": "example"
},
"requestId": "example"
}
}

account_not_found: No account matches the id (and idType) the call named.

workflow_not_found: No API-triggered workflow with that id.

Media typeapplication/json

The one error shape every endpoint answers with.

object
error
required
object
code
required

Stable snake_case code to branch on; see the error table.

string
message
required

For humans; may change.

string
details
object
key
additional properties
requestId
required

Quote it when asking for help.

string | null
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {
"additionalProperty": "example"
},
"requestId": "example"
}
}

recently_triggered: Everyone the call named was reached by this workflow within its resend window.

run_active: The account already has an active run of this workflow.

workflow_has_no_owner: The workflow’s author was removed; someone must take it over before it can send.

workflow_inactive: The workflow is a draft; activate it first.

Media typeapplication/json

The one error shape every endpoint answers with.

object
error
required
object
code
required

Stable snake_case code to branch on; see the error table.

string
message
required

For humans; may change.

string
details
object
key
additional properties
requestId
required

Quote it when asking for help.

string | null
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {
"additionalProperty": "example"
},
"requestId": "example"
}
}

payload_too_large: The request body is too large; details.maxBytes gives the limit.

Media typeapplication/json

The one error shape every endpoint answers with.

object
error
required
object
code
required

Stable snake_case code to branch on; see the error table.

string
message
required

For humans; may change.

string
details
object
key
additional properties
requestId
required

Quote it when asking for help.

string | null
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {
"additionalProperty": "example"
},
"requestId": "example"
}
}

account_archived: The account is archived.

idempotency_key_mismatch: The Idempotency-Key was used before with a different request.

invalid_variable: A variable’s value has the wrong type.

missing_variable: A required variable is missing.

no_recipients: Nobody the call named can be emailed.

recipient_not_found: An email or contact id the call named isn’t a contact at the account.

recipients_not_accepted: The workflow doesn’t send to people a call names, so recipients would be ignored.

recipients_required: The workflow sends to the people a call names, and the call named nobody.

role_field_not_configured: The call named roles, but no contact role field is set on Settings → API.

too_many_recipients: The call names more people than a run may reach.

unknown_role: A role isn’t one of the role field’s slugs; details.validRoles lists them.

unknown_variable: A variable isn’t one the workflow declares.

workflow_not_api_triggered: The workflow isn’t started by the API.

Media typeapplication/json

The one error shape every endpoint answers with.

object
error
required
object
code
required

Stable snake_case code to branch on; see the error table.

string
message
required

For humans; may change.

string
details
object
key
additional properties
requestId
required

Quote it when asking for help.

string | null
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {
"additionalProperty": "example"
},
"requestId": "example"
}
}

rate_limited: Too many requests for this key; retry after Retry-After seconds.

Media typeapplication/json

The one error shape every endpoint answers with.

object
error
required
object
code
required

Stable snake_case code to branch on; see the error table.

string
message
required

For humans; may change.

string
details
object
key
additional properties
requestId
required

Quote it when asking for help.

string | null
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {
"additionalProperty": "example"
},
"requestId": "example"
}
}

internal_error: Something went wrong on Sonora’s side. Retry, and quote requestId if it persists.

Media typeapplication/json

The one error shape every endpoint answers with.

object
error
required
object
code
required

Stable snake_case code to branch on; see the error table.

string
message
required

For humans; may change.

string
details
object
key
additional properties
requestId
required

Quote it when asking for help.

string | null
Examplegenerated
{
"error": {
"code": "example",
"message": "example",
"details": {
"additionalProperty": "example"
},
"requestId": "example"
}
}

Try it

Try it runs the reference's read endpoints, and this one changes data, so it needs an API key with the workflows:trigger scope. Create a key in Sonora under Settings → API and call it from your own code.