API RU
Early access. API keys are issued on request. How to get a key

Stop one lead's automatic sequence. New attempts are blocked, but a send that already started can still complete.

#Request

POST /v1/leads/{id}/stop requires leads:stop and scope access to the lead's workspace and campaign. id identifies one participation: stopping it does not stop the same person in other campaigns or add them to the general stop list.

Send the required Idempotency-Key (1 to 255 printable ASCII characters), Content-Type: application/json and an empty object {}. Extra fields are rejected. Persist a unique key for this operation before requesting; do not reuse an enrollment operation key for a stop.

curl --retry 5 --retry-max-time 300 \
  -X POST https://api.melioralab.io/v1/leads/5a7c3e92-1f4b-4d68-9c2e-7b0a6d4f8e31/stop \
  -H "Authorization: Bearer $MELIORA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $MELIORA_IDEMPOTENCY_KEY" \
  --data-raw '{}'

#Interpreting the response

HTTP 202 returns a command with kind=stop, the target lead_id, empty items and these result fields:

  • result.automation_state=stopped: new automatic attempts are blocked and there is no in-flight send.
  • result.automation_state=stopping: the block is set, but a send already started.
  • result.send_in_flight=true: that send can still complete. This is not delivery confirmation.
  • result.unknown_outcome_message_ids: opaque identifiers of sends with unknown outcomes. Do not parse their format.
  • cleanup_pending=true: stopped work still needs cleanup. This is a command field, outside result.

The command may already be done or done_with_unknown, or remain accepted or running. Poll GET /v1/commands/{id} until a terminal state and completed cleanup. stopped in the result alone does not replace that check.

When reading the lead, inspect automation_stopped, automation_stopped_at, automation_stop_source and automation: state (running, stopping, stopped, unknown), stopped_at, source, send_in_flight, unknown_outcome_message_ids. Read responses allow null for automation_stopped, automation.send_in_flight and automation.unknown_outcome_message_ids when data is not established. null does not mean false or an empty array. The participation status, such as replied, does not have to change on stop.

automation.state=running means no lead-level stop is established; it does not grant permission to send immediately. Campaign pauses and holds still apply. Unlike reads, the stop command result has a definite send_in_flight (true or false) and an array of unknown_outcome_message_ids.

#Event and retries

lead.stopped appears in the event feed once in-flight work and cleanup settle, not immediately at stopping. data.stop contains automation_stopped, stopped_at and source. The schema allows true, false or null for automation_stopped, a time or null for stopped_at, and a string or null for source. An established API stop is expected to have true and api, but those are not schema constants. It confirms stopped automation, not certainty about every past send.

Retrying the same key, lead and body returns the same command in its current state. After 429/503 wait for Retry-After; after a lost connection preserve the same key. Stopping again with a new key is also safe: it does not resume the sequence, preserves the original stop time, and creates no second transition or second lead.stopped event. A different lead or operation with an already used key gives 422 idempotency_key_reused.

#Budget and errors

Stop weight is 1 with a separate budget: up to 2 concurrent requests, 60 per minute per key and 120 per minute per organization. It does not consume the organization's normal minute budget or normal concurrency slots. Limits do not guarantee an immediate response; retry 429/503 after the required delay.

403 scope_required means a missing permission; 403 api_write_disabled means writes are not enabled yet. An invalid body gives 422 invalid_request, an invalid header 400 invalid_parameter, and an inaccessible or missing lead 404 not_found. After 503 rate_limiter_unavailable, retry the original request with the same key. See errors and limits.