Partner API Create candidates, collect documents and references, retrieve the compliance pack.

Get an API key

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.
Idempotency-Key<your own retry id>optional
Optional. Send it and a retry of the same request replays the first outcome instead of repeating the write. 1–255 characters. Per account, per route, per candidate.

Request fields

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

Status codes

4024xx
Your plan has ended (code: "no_subscription"), or this month’s messages are used up and there is no open 24-hour chat with this candidate (code: "over_message_quota"). Nothing was sent. A reply inside an open chat is never refused for the message limit.
5035xx
We could not check your plan just now (code: "billing_unavailable"). Nothing was sent; retry shortly.
2002xx
Sent. Check delivery later via Retrieve messages, keyed on message_id — occasionally null (see notes below); the message was still sent either way. With an Idempotency-Key already used for this candidate, this is the ORIGINAL answer again with replayed: true inside data — nothing is sent a second time.
4004xx
Missing/empty body, over the length cap, or an Idempotency-Key over the length limit.
A non-empty `body` is required`body` exceeds the maximum length of {max} charactersThe Idempotency-Key header must be at most 255 characters.
4014xx
Missing, malformed, unknown, revoked or expired key. Every authentication failure looks the same — see Authentication.
4034xx
The key’s user has the viewer team role, or their account could not be read just then (retry) — or the key was created Read only (code: "key_read_only", refused before anything else). Checked before the body or any id — see Authentication.
Your team role doesn't allow this. Ask your team's admin or owner.This API key is read-only. Create a full-access key to make changes.
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, 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), or another request with this Idempotency-Key is still in flight.
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.A request with this Idempotency-Key is already in progress.
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 "Idempotency-Key: <your own retry id>" \
-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.