Send a review request

Send a review request

POST/api/v1/review-requests

scope reviews:sendIdempotent

Sends one contact a message asking for a review, with a link that is theirs alone, and returns the request. The message goes out on the channel the contact most recently used. On WhatsApp, outside the 24-hour window, it is sent as the review template the account configured in Reviews → Settings; inside the window, and on Messenger and Instagram, it is a plain message. Leave form_id out to use the account’s default form. When it cannot be sent the answer is 422 unprocessable and reason says why: contact_not_found, form_not_found, no_review_form (the account has no active form), form_required (several forms and no default — send form_id), template_required (the WhatsApp template is missing or not approved), outside_window (Messenger or Instagram, more than 24 hours since the customer wrote), no_conversation (no way to reach the contact) or send_failed. A request that failed to send is recorded as failed and does not count toward the monthly limit; reaching that limit returns 402 plan_limit_reached. Send an Idempotency-Key header so a retry does not message the customer twice.

Body

application/json
NameTypeDescription
contact_idrequired
string (uuid)Who to ask
form_idoptional
string (uuid)Which form to send. Defaults to the account’s default form
service_hintoptional
stringWhat they experienced, for the template body, e.g. "your website launch"
Request
curl -X POST "https://your-crm.example.com/api/v1/review-requests" \
  -H "Authorization: Bearer $RAABTA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2a9e-3b4d-4c5e-8f7a-9b0c1d2e3f4a" \
  -d '{
    "contact_id": "9d7e4c11-5a2b-4f7c-8e3d-2a1b0c9d8e7f",
    "service_hint": "your website launch"
  }'
Response · 201 Created
{
  "data": {
    "id": "6d5c4b3a-2f1e-4d0c-9b8a-7f6e5d4c3b2a",
    "contact_id": "9d7e4c11-5a2b-4f7c-8e3d-2a1b0c9d8e7f",
    "form_id": "f0a1b2c3-d4e5-4f6a-8b7c-9d0e1f2a3b4c",
    "conversation_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "channel": "whatsapp",
    "source": "api",
    "status": "sent",
    "review_url": "https://raabtahq.online/r/3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c",
    "sent_at": "2026-09-02T10:05:02.000Z",
    "clicked_at": null,
    "completed_at": null,
    "error_message": null,
    "created_at": "2026-09-02T10:05:00.000Z",
    "updated_at": "2026-09-02T10:05:02.000Z"
  }
}

Response

Wrapped in { data: … }
NameTypeDescription
idrequired
string (uuid)UUID
contact_idrequired
string (uuid) | nullWho was asked; null if the contact was since deleted
form_idrequired
string (uuid)The form the link opens
conversation_idrequired
string (uuid) | nullThe thread the request was sent in
channelrequired
string (enum)The channel it was sent on: the one the contact most recently usedwhatsappmessengerinstagramwebchatpersonal_whatsappemail
sourcerequired
string (enum)Where it came from: a member, a bulk send, an automation, the assistant, or this APImanualbulkautoaiapi
statusrequired
string (enum)pending, then sent or failed, then clicked when the link is opened and completed when a review is submittedpendingsentfailedclickedcompleted
review_urlrequired
stringThe customer’s own link. Anyone holding it can submit the review, once
sent_atrequired
string (date-time) | nullWhen the message went out
clicked_atrequired
string (date-time) | nullWhen the customer first opened the link
completed_atrequired
string (date-time) | nullWhen the review was submitted
error_messagerequired
string | nullWhy it failed, when status is failed
created_atrequired
string (date-time)ISO 8601 timestamp
updated_atrequired
string (date-time)ISO 8601 timestamp

Errors

StatusCodeWhen
400bad_requestThe request could not be parsed: malformed JSON, an invalid cursor, or a query parameter of the wrong shape.
400validation_errorThe body or query failed validation. `details` lists each failing field with a `path` and a `message`.
401unauthorizedNo usable API key: the Authorization header is missing or malformed, or the key is unknown, revoked or expired. The three are deliberately indistinguishable.
402plan_limit_reachedThe account has reached a plan limit for this resource. `details[0].limit` is the cap; ask the account owner to raise it.
403forbiddenThe key is valid but lacks the scope this endpoint requires, or the request came from an address outside the key’s IP allowlist. The message says which.
403account_suspendedThe account this key belongs to is suspended. Rotating the key will not help; contact support.
409conflictThe request conflicts with current state: a duplicate phone number on create, an invalid state transition, or an idempotent request that is still in flight.
422unprocessableThe request was well-formed but cannot be carried out. `reason` is a stable string saying why (for example `outside_window` or `stage_not_in_pipeline`).
429rate_limitedThe per-key budget, or the per-IP budget for failed authentication, is exhausted. Honour `Retry-After` before retrying.
500internalSomething failed on our side. Safe to retry with the same Idempotency-Key; quote `request_id` if it persists.