Send a message

Send a free-text WhatsApp message to a candidate, on the recruiter’s behalf.

POST/api/v1/candidates/{id}/messages#

Headers

X-Api-Keyonb_live_<key_id>_<secret>required
Your issued Partner API key — see Authentication.

Request fields

bodystringrequired
Non-empty, ≤2000 characters — the same cap the dashboard’s own reply composer is sized for.

Status codes

2002xx
Sent. Check delivery later via Retrieve messages, keyed on message_id — occasionally null (see notes below); the message was still sent either way.
4004xx
Missing/empty body, or over the length cap.
A non-empty `body` is required`body` exceeds the maximum length of {max} characters
4014xx
Missing, malformed, unknown or revoked key. Every authentication failure looks the same — see Authentication.
4044xx
Unknown, cross-tenant, or sandbox-hidden. One outcome, never a 403 — even one this route’s own send seam would otherwise return.
Not found
4094xx
Consent not granted, or the candidate cannot be messaged right now (opted out, data processing paused, messaging disabled, account scheduled for deletion, or the WhatsApp session window has closed — see Send a template for a compliant fallback).
This candidate has opted out of messages.This candidate's data processing is paused — a message cannot be sent.Messaging is currently disabled for this candidate.This account is scheduled for deletion — a message cannot be sent.This candidate hasn't replied on WhatsApp in over 24 hours — a free-form message can't be sent outside the messaging window.This candidate has received too many messages recently — try again shortly.This candidate's status could not be verified. Try again shortly.This message could not be sent. Try again shortly.
4294xx
Per-key/per-account rate limit, OR this candidate’s own outbound message throttle.
Too many requests — please try again shortly.
5005xx
The service is temporarily unavailable.
This resource is temporarily unavailable. Try again shortly.
5025xx
The send transport failed.
This message could not be sent. Try again shortly.
5035xx
This candidate’s status could not be verified — retry.
This candidate's status could not be verified. Try again shortly.

Delivery status lives on Retrieve messages

This response only confirms the send was accepted. Poll GET /api/v1/candidates/{id}/messages and match message_id against id in that page’s messages array for delivery_status/delivery_error.

  • Sends VERBATIM text — never an approved template. Outside the 24-hour WhatsApp session window, this endpoint refuses (409) rather than falling back to a template; see Send a template for the compliant door onto a candidate who has gone quiet.
  • The candidate must have granted consent — a candidate mid-onboarding who has not yet consented cannot be messaged this way.
  • Sending or pausing does not require the bot to be paused first — but see Pause or resume the bot if you want the bot to stop replying while your own recruiter is handling the thread.
  • message_id can be null on a 200 — the WhatsApp message was still sent; this only means the row backing it could not be resolved yet. Fall back to matching sent_at and body on Retrieve messages in that case.
cURL
curl -X POST \
"https://rca-onboardly.com/api/v1/candidates/<candidate id>/messages" \
-H "X-Api-Key: $ONB_KEY" \
-H "Content-Type: application/json" \
-d '{
"body": "Thanks for sending your DBS — we just need Proof of Address next."
}'
Request body
{
"body": "Thanks for sending your DBS — we just need Proof of Address next."
}
200 · Response
{
"message_id": "b2f4c1a0-7e3d-4a9c-8b1f-2d6e5a9c3f70",
"delivery_status": "sent",
"sent_at": "2026-09-18T10:14:02Z"
}

Delivery status is not returned here — poll Retrieve messages and match message_id.