Get in Touch

Have a question about the platform, need help with your integration, or want to discuss partnership opportunities and enterprise pricing? Drop us an email — we’ll do our best to get back to you within 3–4 hours.

contact@fiwano.com
Documentation menu

Working with an AI agent? Download the full documentation as a Markdown file to use as context.

Download full .md

Sending Messages

Fiwano has three send endpoints — plain text, media, and WhatsApp templates. All take a channel_id and a recipient. The recipient format depends on the channel (phone number for WhatsApp, IGSID for Instagram, PSID for Facebook) — see the recipient row in Capabilities. Full request/response schemas are in the API Reference; this page is the task guide.

Send WhatsApp messages with the API

For a normal WhatsApp reply inside the 24-hour customer service window, use the plain text endpoint below with a WhatsApp channel_id and the recipient's phone number. You authenticate with your Fiwano X-API-Key; you do not need a separate Meta or WhatsApp API key in your application.

Outside the 24-hour window, WhatsApp requires an approved template message. That uses /api/v1/messages/send-template and is described in Template messages. Instagram DM and Facebook Messenger use the same text endpoint for ordinary replies, with IGSID or PSID as recipient.

Text messages

POST /api/v1/messages/send — works on all channel types.

curl -X POST https://fiwano.com/api/v1/messages/send \
  -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"channel_id": "a1b2c3d4e5f67890", "recipient": "1234567890", "text": "Hello! Your order is ready."}'

The response carries a message_id (a Fiwano UUID) that every later delivery-status webhook references. Text has a per-platform length cap (WhatsApp 4096, Facebook 2000, Instagram 1000) — oversize text is rejected with 400 text_too_long before Meta is called. Fiwano does not auto-split; split on your side to preserve your own chunking and ordering. The text value must contain at least one non-whitespace character; empty or whitespace-only values are rejected with 422 before Meta is called. Leading and trailing whitespace in otherwise valid text is preserved. See Capabilities.

recipient is trimmed of surrounding whitespace, then checked before Meta is called: an empty value, a value without any digit (for example a serialized object such as [object Object]), or a non-numeric PSID/IGSID on a Messenger/Instagram channel is rejected with 400 invalid_recipient (see Errors). No further shape rules are applied — a WhatsApp number that Meta can interpret is passed through as-is, and any rejection Meta makes itself still comes back as status: "failed".

Media messages

POST /api/v1/messages/send-mediaPro license required. Meta fetches the file directly from media_url; Fiwano never downloads or stores it. Pass media_type (image, audio, video, document) and an HTTPS media_url.

Use a signed URL for non-public content — S3/GCS/R2 presigned, Azure SAS, or an HMAC-signed URL on your own server, with expiry ≥ 20 min so background retries can still fetch it. A public URL is reachable by anyone who learns it.

Keep files small and hosting fast. Meta downloads the file while your request is waiting, so a compressed image on a fast host is accepted in a couple of seconds, while a large file on a slow host can take Meta a minute or more. Smaller files mean faster, more predictable delivery and fewer sends that finish in the background — see Response time.

curl -X POST https://fiwano.com/api/v1/messages/send-media \
  -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "channel_id": "a1b2c3d4e5f67890",
    "recipient": "1234567890",
    "media_type": "image",
    "media_url": "https://my-bucket.s3.amazonaws.com/photo.jpg?X-Amz-Signature=...&X-Amz-Expires=1800",
    "caption": "Your order photo"
  }'

Always check success and status. Permanent failures include a Meta error_code — for example 131052 when Meta cannot download the URL. Failures that can recover, including 131053 processing/fetcher failures and 131056 pair rate limits, return queued and use the same durable retry schedule as text. File-size caps are in Capabilities and the full error-code table is in Errors.

Response time

POST /messages/send-media is synchronous and can be slow. Fiwano never downloads your file: we hand Meta the media_url and Meta fetches it inside your request. The wait is therefore proportional to the file size and to how fast your own hosting serves it. A 12-second call for a large file is normal. Fiwano waits for Meta for up to 30 seconds; if Meta has not answered by then, the call returns queued and Fiwano completes the send in the background — see Delivery and retries.

Text and template sends are not affected — they carry no file and typically complete in well under a second.

Set your HTTP client timeout to at least 35 seconds for send-media. Some environments cap this for you and cannot wait that long — AWS API Gateway stops at 29 seconds, and serverless functions often default to 10–15 seconds.

If your client times out, the message may still have been sent. Meta can accept it after you stopped waiting. Resending then delivers it twice. Retry only after confirming the message is absent from the conversation.

To keep media sends fast, serve media_url from storage close to your users (S3/GCS/R2 with a CDN) and keep files well under the size caps.

Template messages

POST /api/v1/messages/send-templateWhatsApp only, Pro required. Use a pre-approved template to start a conversation outside the 24-hour window (see Capabilities). Only APPROVED templates can be sent — to create and manage them, see WhatsApp Templates.

Provide variable values keyed by component. Positional templates ({{1}}, {{2}}) take arrays:

curl -X POST https://fiwano.com/api/v1/messages/send-template \
  -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "channel_id": "a1b2c3d4e5f67890",
    "template_name": "order_confirmation",
    "language": "en_US",
    "recipient": "1234567890",
    "variables": {
      "header": ["Summer Sale"],
      "body": ["Pablo", "ORD-123", "25%"],
      "buttons": [{"index": 0, "value": "promo25"}]
    }
  }'

Named templates ({{customer_name}}) take objects:

  -d '{
    "channel_id": "a1b2c3d4e5f67890",
    "template_name": "welcome_message",
    "language": "en_US",
    "recipient": "1234567890",
    "variables": {"body": {"customer_name": "Pablo", "order_number": "ORD-123"}}
  }'

Omit variables entirely if the template has none.

Template sends return the same response shape as text and media sends. The message_id is a Fiwano UUID; keep it to correlate later delivery webhooks:

{
  "success": true,
  "message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "error": null,
  "error_code": null,
  "status": "sent"
}

Delivery and retries

All three send endpoints return 200 with the common success, message_id, error, error_code, and status fields, because what happens after Meta accepts the request matters:

  • sent — Meta accepted it. Track the rest via delivery-status webhooks (message.delivered / read / failed) — see Receiving Messages.
  • queued — Fiwano is completing the send in the background and message_id is already final. This happens after a transient Meta failure (network, 5xx, rate limit) — retried up to 7 times over ~20 min, with an early-warning email after 3 failed retries and a final email if they're exhausted — and when Meta takes longer than 30 seconds to answer, which occasionally happens with large media — see slow Meta responses. Track the outcome through the delivery-status webhooks; do not resend on your side.
  • failed (success: false) — the request will not be retried. For send and send-media, this means Meta rejected the message permanently (a recipient the Page or number cannot message, oversize text or media, malformed payload, a closed 24h window, or an action Meta denies for the account — see send error codes), and the channel owner is emailed. A request Fiwano itself refuses before calling Meta (text_too_long, invalid_recipient, recipient_equals_sender) answers with an HTTP 400 instead, not with failed. send-template does not retry automatically, so any Meta send error is returned as failed; the caller can decide whether and when to resend.

So 200 does not by itself mean "delivered" — always read success and status.

Frequently asked questions

How do I send a WhatsApp message with the API?

Call POST /api/v1/messages/send with your Fiwano API key, a WhatsApp channel_id, the recipient phone number and text. The same endpoint also sends free-form replies on Instagram DM and Facebook Messenger; WhatsApp templates use the separate send-template endpoint.

Do I need a separate WhatsApp API key from Meta?

No. You use your Fiwano X-API-Key. Fiwano connects the underlying WhatsApp, Instagram or Facebook channel through Meta OAuth and handles the Meta access token behind the API.

Can I send WhatsApp messages outside the 24-hour window?

Yes, but only with approved WhatsApp templates. Free-form WhatsApp text messages are for replies inside the 24-hour customer service window; templates are the official way to start or reopen a WhatsApp conversation.