Back to Nodes

Fiwano

Last updated Oct 6, 2026

Verified n8n community nodes for the Fiwano messaging platform API (WhatsApp, Instagram, Facebook Messenger)

253 Weekly Downloads
745 Monthly Downloads

Included Nodes

Fiwano
Fiwano Trigger

Description

n8n-nodes-fiwano

n8n verified community node for Fiwano — a unified messaging API for WhatsApp, Instagram DM, and Facebook Messenger.

What is Fiwano?

Fiwano is a verified Meta Tech Provider that abstracts the complexity of WhatsApp Cloud API, Instagram Messaging API, and Facebook Messenger API into a single, consistent REST API. Connect your Meta-verified business accounts once via simple Facebook auth — no Meta developer portal, no app creation, no Meta app review.

Fiwano is a messaging API, not a full Meta platform API. It does one thing well: receive inbound messages and send replies (plus WhatsApp templates) across WhatsApp, Instagram DM, and Messenger. It deliberately stays out of comments, posts, stories, ads, and page analytics — just conversations with people.

Key benefits:

  • Official Meta APIs only — built on WhatsApp Cloud API, Instagram Messaging API and Facebook Messenger API. No browser automation, no unofficial client simulation, no account ban risk. Production-safe at any scale.
  • One API for three channels — identical request format across WhatsApp, Instagram DM, and Facebook Messenger
  • Real-time webhooks — incoming messages and delivery statuses delivered to your endpoint, HMAC-signed
  • WhatsApp template management — create, manage, and send approved templates directly from the API
  • Secure by default — tokens encrypted at rest, message content is not stored permanently
  • Built for AI assistants, CRMs, helpdesks, and any product that needs conversational messaging at business scale.

    7-day free trial — no credit card required.

    License Tiers

    One license covers a slot bundle: 1 WhatsApp + 1 Instagram + 1 Facebook Messenger channel, with unlimited messages.

    | Tier | Monthly | Capabilities |
    |——|———|————-|
    | Starter | $12 | Text messages in/out and delivery statuses |
    | Pro | $19 | Everything in Starter + inbound media and files, outbound media via HTTPS URL (signed URLs supported), WhatsApp template management and sending |

    New accounts start with a 7-day free trial on the Pro tier (full functionality).

    Nodes

    | Node | Type | Description |
    |——|——|————-|
    | Fiwano | Action | Send messages, manage channels, check subscriptions and available slots, WhatsApp templates, contact profile enrichment, redirect URIs |
    | Fiwano Trigger | Webhook Trigger | Receive incoming messages and delivery status webhooks |

    Action node — operations

    | Resource | Operations |
    |———-|———–|
    | Message | Send Text, Send Media, Send Template (WhatsApp) |
    | Channel | Get Many, Get, Generate OAuth URL, Exchange OAuth Code, Update (webhook settings + subscription binding), Deactivate |
    | Media | Download (saves received file as binary data) |
    | Contact | Get Profile (Instagram, Facebook — enriches sender with name, profile picture, follower count) |
    | Template | Get Many, Get, Create, Update, Delete (WhatsApp only) |
    | Redirect URI | Get Many, Add, Delete |
    | Subscription | Get Many (subscriptions, assigned channels, available slots by channel type and tier) |

    Trigger node — events

    The trigger starts your workflow for any of these events:

    | Event | Channels |
    |——-|———|
    | message.received | WhatsApp, Instagram, Facebook |
    | message.echo | WhatsApp (Coexistence only), Instagram, Facebook |
    | message.delivered | WhatsApp, Instagram, Facebook |
    | message.read | WhatsApp, Instagram, Facebook |
    | message.sent | WhatsApp |
    | message.failed | WhatsApp, Instagram, Facebook |
    | conversation.referral (beta) | Instagram, Facebook |

    Choose the events in the trigger’s Event Types — a new trigger starts with Message Received only; nothing you have not selected is delivered. HMAC-SHA256 signature verification is built in.

    —

    Installation

    Fiwano is verified by n8n and can be installed directly from the n8n editor by an instance owner or admin.

    n8n app (verified community node)

    1. Open the editor canvas and open the nodes panel with + or N.
    2. Search for Fiwano.
    3. Select Fiwano under More from the community.
    4. Click Install.
    5. Add the Fiwano or Fiwano Trigger node to your workflow.

    See n8n’s verified community node installation guide for details. On n8n Cloud, installation may need to be enabled by the instance owner in the Cloud Admin Panel. On self-hosted n8n, the related community-node settings are controlled by environment variables.

    Manual install fallback

    Use manual npm installation only when the in-app verified-node installation is unavailable in your environment.

    #### Self-hosted npm

    mkdir -p ~/.n8n/nodes
    cd ~/.n8n/nodes
    npm install n8n-nodes-fiwano
    

    Restart n8n

    Self-hosted Docker

    No custom image required — install Fiwano in-app via Settings → Community Nodes (or the nodes panel above). The package is stored in the n8n data volume, so keep ~/.n8n (/home/node/.n8n in the official image) on a persistent volume and it survives restarts and upgrades.

    To bake it into a custom image instead, follow n8n’s community-node installation guide.

    —

    Credentials

    1. Sign up at fiwano.com and create an API key in API Keys
    2. In n8n: Credentials → Add → Fiwano API → paste the key (starts with miplive)
    3. (Optional) Set a Webhook Secret on the credential to reuse one HMAC secret across all workflows — the trigger and the Exchange OAuth Code / Update operations fall back to it when their own secret field is empty.

    All Fiwano action nodes use this credential. The Fiwano Trigger node works without credentials in manual mode (it only verifies the webhook signature you configure per-channel). Add the same credential to the trigger only if you want it to auto-register its webhook on your channels — see Setting Up the Trigger.

    —

    Connecting a Channel

    Two ways to connect a channel — pick based on whose channel it is:

  • Your own channels → the Fiwano portal UI (no code). Simplest when you just need your own WhatsApp / Instagram / Facebook in your automation.
  • Your customers’ channels → the API (the nodes below, or the Connect a Channel workflow). This embeds a “connect your channel” step into your own product, so an external client authorizes their own Meta account through your interface — they never need a Fiwano account.
  • The API flow is Facebook OAuth, run once per channel (WhatsApp number / Instagram account / Facebook Page):

    1. Add a Fiwano node → Resource: Channel → Operation: Generate OAuth URL
    – Select channel type, provide your redirect URI (must be registered via Redirect URI → Add)
    – Run the node → copy the setup_url from the output
    2. Open that URL in a browser and authorize the page(s)
    3. Add another Fiwano node → Channel → Exchange OAuth Code
    – Paste the code from the redirect URL query parameter — it is single-use and short-lived, so exchange it promptly
    – On failure the redirect carries error instead: accessdenied (user cancelled or did not complete the Meta dialog), slotoccupied (the user connected a different Meta account than the one holding your subscription slot — message names the channel to reconnect or release), sessionexpired (the setup URL expired; generate a new one) or setupfailed (anything else). Branch on error only — the companion message is free-form English for display and may change
    – Optionally set webhookurl and webhooksecret in Additional Fields
    4. The response contains channel_id — save it for all subsequent nodes

    The same Generate OAuth URL operation also reconnects an inactive channel — there is no separate reconnect operation. Run the flow again for the same Meta account and Fiwano updates the existing channel, so Exchange OAuth Code returns the channel ID you already stored.

    Alternatively, manage everything from the Fiwano portal UI.

    Turning webhook delivery off

    Channel → Update → additional field Clear Webhook URL removes the webhook from a
    channel. Event delivery stops until a URL is set again; the channel keeps its secret and
    its event selection, so restoring is just setting the URL back.

    Leaving the Webhook URL field blank does not clear it — clearing is always the
    explicit toggle.

    Channel health

    Every channel returned by Channel → Get and Channel → Get Many carries health.
    health.status is ok, or action_required when Meta no longer lets Fiwano work with
    the account or number (access or a permission revoked, a WhatsApp number removed, an
    account blocked by Meta); health.reason is Meta’s error text and health.since when it
    was detected. The channel stays active, but sends may fail until the cause is fixed in
    Meta or the same account is connected again with Generate OAuth URL. A scheduled
    workflow that checks health.status can alert you. See
    Channel health.

    Subscription slots

    Each subscription grants one slot per channel type — one WhatsApp, one Instagram, one Facebook. Use Subscription → Get Many to see what is free:

  • availableslots.type>.total > 0 means a new channel of that type can be connected.
  • It does not gate reconnecting an inactive channel: a deactivated channel keeps its slot, and that reserved slot is what lets you bring it back.
  • assigned_channels shows which channel sits in each slot. The reverse lookup is subscription.id on the channel itself in Channel → Get Many.
  • Generate OAuth URL tells you when a connect cannot go ahead: HTTP 402 means the account has no active subscription at all; HTTP 409 means subscriptions exist but every slot of that channel type is taken — the error lists the channels holding them, so you know what to reconnect or release. (In the API a subscription is what the portal’s Billing page calls a license — same thing.)

    Deactivate is a soft delete. It stops the channel sending and receiving, but keeps its ID, history and its subscription slot. Deactivating alone does not free a slot.

    To actually replace a channel, release the slot in a second step with Channel → Update → Release Subscription Slot:

    Channel → Deactivate            (channel_id = old channel)
    Channel → Update                (channel_id = old channel, Release Subscription Slot = true)
    Channel → Generate OAuth URL    (user connects the new Meta account)
    Channel → Exchange OAuth Code   (new channel takes the freed slot)
    

    Setting Subscription ID to an actual ID instead moves the channel to that subscription — no downtime, and the channel does not have to be deactivated first. An empty Subscription ID is ignored; releasing is always the explicit toggle.

    > Releasing a slot is effectively permanent. Once another channel takes the freed slot, the released one can no longer be reconnected until a slot is free again. Treat it as retiring that channel, not pausing it. Moving a channel to a Starter subscription stops media and template sending immediately.

    —

    Setting Up the Trigger (Webhooks)

    The Fiwano Trigger node starts a workflow when a message arrives on your channel. There are two ways to wire it up.

    Option A — Automatic setup (recommended)

    Let the trigger register its own webhook on your channel(s).

    1. Add Fiwano Trigger and add your Fiwano API credential to it (needed for the auto modes — they error at activation if it’s missing)
    2. Set Webhook Auto-Setup:
    – All Active Channels — wire every connected channel (WhatsApp + Instagram + Facebook) that isn’t already pointing elsewhere to this one trigger. One flow, three platforms.
    – Specific Channel — register on a single Channel ID (takes it over even if it already has a webhook).
    3. Choose Event Types — these are written to each channel’s webhook_events (overwriting what was there). Leave it empty to have auto-setup wire only the URL and leave the channel’s existing events unchanged (manage them in the portal or via Channel → Update). New nodes start with message.received selected.
    4. (Recommended) Set a Webhook Secret to verify incoming signatures — preferably on the credential (reused everywhere; see Credentials). The trigger’s own Webhook Secret field overrides it.
    5. Save and activate the workflow — the trigger PATCHes the channel(s) with its webhook URL, events, and secret. Deactivating clears the webhook URL again (in “All” mode, only on channels still pointing at this trigger).

    Auto-setup requires n8n’s Production URL to use HTTPS and not point to
    localhost, 127.0.0.0/8, or ::1. If n8n resolves an HTTP or loopback
    Production URL, activation stops before changing any Fiwano channel and tells
    you to configure WEBHOOK_URL, restart n8n, or use Manual setup. A domain that
    merely contains the word localhost (for example localhost.example.com) is
    not treated as localhost.

    Option B — Manual setup

    Set Webhook Auto-Setup to Manual (no credential needed on the trigger).

    1. Create a workflow, add Fiwano Trigger, choose event types (default: message.received)
    2. Save and activate the workflow — n8n assigns a permanent webhook URL
    3. Open the Fiwano Trigger node and copy its Production URL (format: https://your-n8n.example.com/webhook/)
    4. In a Fiwano node → Channel → Update, set the fields below, then execute the node once:
    – channel_id — your channel
    – webhook_url — the Production URL from step 3
    – Leave webhook_secret empty to auto-generate one, or provide your own
    5. The response includes webhook_secret — copy it into the Webhook Secret field in the Trigger node
    6. Re-save the workflow

    > n8n must be publicly accessible. Fiwano delivers webhooks over the internet. Local localhost won’t work — use a reverse proxy, ngrok, or n8n Cloud.

    > Event filter vs. channel subscription. The trigger’s Event Types filter is applied on the n8n side (empty = process every event that arrives). In automatic setup the same selection is also written to the channel’s webhook_events, overwriting what was there — except when it’s empty, in which case auto-setup leaves the channel’s events untouched and you configure them yourself (portal or Channel → Update). In manual setup, make sure the events you enable on the channel match what the trigger expects.

    > When auto-setup runs. Only on workflow activation / deactivation (and when n8n restarts active workflows) — never per message, so it adds no per-message overhead.
    >
    > – Non-destructive, and silent about it. “All Active Channels” only wires channels that aren’t already pointing somewhere else; a channel wired to another URL is left alone — and the workflow still activates without an error. So if one channel isn’t responding, check whether its webhook points elsewhere. To take a channel over deliberately, clear its webhook or use Specific Channel.
    > – Deactivating removes the webhook from the channels pointing at this trigger — it clears the webhook URL only, it does not delete the channel, messages, or any data. While deactivated, inbound events are neither relayed nor stored — reactivate to resume delivery.
    > – Clean up before removing. Deactivate the workflow (don’t just delete it, and don’t remove the credential first) so the trigger can clear the webhook. If cleanup can’t run, a channel keeps pointing at an inactive n8n URL and Fiwano will log delivery failures and email you until you clear it (via Update or the portal).
    > – Connect a new channel after activating? Re-activate the workflow so it gets wired.

    Webhook Payload Structure

    Every event from Fiwano follows the same top-level shape:

    {
      "event": "message.received",
      "channel_id": "a1b2c3d4e5f67890",
      "channel_type": "whatsapp",
      "timestamp": "2025-01-15T10:30:00Z",
      "data": { ... }
    }
    

    Key fields available in expressions after the trigger:

    | Expression | Value |
    |—|—|
    | {{ $json.channel_id }} | Channel that received the message |
    | {{ $json.channel_type }} | whatsapp / instagram / facebook |
    | {{ $json.data.from }} | Sender ID — use as recipient when replying |
    | {{ $json.data.from_name }} | Sender name (WhatsApp only; null on Instagram/Facebook) |
    | {{ $json.data.text }} | Message text (for type: text messages) |
    | {{ $json.data.type }} | text, image, audio, video, document, share, or unsupported (see below) |
    | {{ $json.data.replyto.messageid }} | Present when the user replied to a specific message: the id you already hold for it — your send’s messageid (UUID) or the data.messageid of an earlier inbound message (see below) |
    | {{ $json.data.replyto.story.url }} | Instagram reply to your story: the story media link; replyto.story.id, .expiresat, .linkurl alongside |
    | {{ $json.data.sharetype }} | On type: "share" — post, reel, or storymention |
    | {{ $json.data.share.url }} | On type: "share" — link to the shared post / reel / story; share.expires_at is set for story mentions only |
    | {{ $json.data.media.mediaid }} | ID to download file via GET /api/v1/media/{mediaid} (Pro license) |
    | {{ $json.data.media.voice }} | true for WhatsApp voice messages (boolean, WA only; omitted for IG/FB) |
    | {{ $json.data.media.sticker }} | true when the image is a sticker (WhatsApp WebP, Facebook); omitted for ordinary photos |
    | {{ $json.data.media.sticker_id }} | Facebook only — Meta’s sticker id; send it back with Media Type sticker |
    | {{ $json.data.media.downloadurl }} | Authenticated download URL — fetch with your X-API-Key. null if download from Meta failed. Cannot be used directly as mediaurl for outbound sends — re-host the bytes first. |
    | {{ $json.data.media.mime_type }} | MIME type of the received file |
    | {{ $json.data.media.file_size }} | File size in bytes |
    | {{ $json.data.media.filename }} | Original filename (documents only; null otherwise) |
    | {{ $json.data.media.duration_ms }} | Duration in ms (audio/video only; null otherwise) |
    | {{ $json.data.media.expires_at }} | ISO 8601 expiry timestamp — file deleted after this time |
    | {{ $json.data.media.error }} | Present only when Fiwano could not download the file from Meta; download_url is then null |
    | {{ $json.data.caption }} | Text Meta sent together with the media (all channels), or the caption of a shared post / reel. Plain text messages use data.text instead |
    | {{ $json.data.referral.text }} | (beta) Present when the conversation started from an ad or an m.me / ig.me link: the ad copy the user saw; referral.source, .image_url, .ref, .raw alongside (see Referral context) |
    | {{ $json.data.unsupported_type }} | On type: "unsupported" — what Meta actually sent (see below) |
    | {{ $json.data.upgrade_required }} | "pro" if channel lacks a Pro license for this message |
    | {{ $json.data.status }} | On message.delivered / read / failed — "delivered", "read", "failed" |
    | {{ $json.data.errors }} | On message.failed — Meta’s raw error array, e.g. [{"code":131047,"title":"..."}]. data.error holds the readable summary |

    Messages with several attachments

    When a user sends an album (several files in one Instagram or Facebook message), Fiwano delivers one message.received event — and one trigger execution — per attachment. There is never an array of events in a single execution, so a workflow that handles one file already handles albums.

    What to rely on:

  • Events arrive in Meta’s attachment order.
  • data.caption is on the first event only.
  • The first event keeps Meta’s own message ID; later parts get .2, .3, … appended. Treat data.message_id as an opaque idempotency key — do not parse the suffix and do not pass the ID back to Meta.
  • Retries are independent per event, so a failing endpoint can see a later part before a retried earlier one. Do not assume strict arrival order.
  • One failed download does not suppress the rest: that event carries media.download_url: null and media.error.
  • WhatsApp is unaffected — Meta already delivers each WhatsApp media message separately.

    Button taps and menu choices

    When a user picks one of the options you offered — a WhatsApp template quick-reply button, a WhatsApp interactive button or list row, an Instagram/Messenger quick reply, or a Messenger/Instagram postback (Get Started, ice breakers, persistent menu) — it arrives as an ordinary type: "text" whose data.text is the label the user saw. One text branch handles typed answers and taps alike; there is no separate event and no machine id for the button. Which message the button belonged to is in data.replyto (a WhatsApp template tap always quotes the template send, so replyto.messageid is the messageid you got from Message → Send Template).

    Replies — data.reply_to

    When the user replies to a specific message (WhatsApp “Reply”, Instagram/Messenger swipe-to-reply), data.replyto.messageid is the id you already have for the quoted message: the Fiwano UUID if you sent it through Fiwano (or received it as message.echo), or the data.messageid of an earlier inbound message. Compare it with the ids you stored to know what was quoted. An Instagram reply to your story carries data.replyto.story (id, url, expiresat, linkurl) instead of a message id. reply_to is absent when the message is not a reply, and also appears on message.echo.

    Shares — type: "share"

    On Instagram and Facebook Messenger a user can share a post or a reel into the chat, or mention your account in their story. These arrive as type: "share" with data.sharetype (post, reel, storymention), data.share.url (Meta’s link to the content; a story mention links to the story media), data.share.expires_at (story mentions only — about 24 h) and data.caption (the post caption, when Meta provides it). Nothing is downloaded and there is no data.media block: a post belongs to its author, and Meta does not allow storing story media.

    Referral context — ads and links (beta)

    When a conversation starts from a Click-to-WhatsApp, Click-to-Instagram or Click-to-Messenger ad, or from an m.me / ig.me link with a ref parameter, the message.received that follows the click carries data.referral. An ice breaker or Get Started tap arrives as type: "text" and carries it the same way; for a message with several attachments it is on the first part only.

    > Beta until November 2026. The four normalised keys (source, text, image_url, ref) and the conversation.referral event may be adjusted; raw is guaranteed to stay exactly as it is, so anything built on raw is safe. If you plan to rely on the normalised keys or on conversation.referral, tell us at support@fiwano.com: should anything change, we will let you know before it does.

    | Expression | Value |
    |—|—|
    | {{ $json.data.referral.source }} | ad, link (m.me / ig.me with ref), product (Instagram Shop). Open set: another value Meta reports arrives in lower case, unknown when Meta sent none |
    | {{ $json.data.referral.text }} | The ad copy the user saw (WhatsApp: headline and primary text joined by a newline; Instagram / Messenger: the ad title). null for links |
    | {{ $json.data.referral.image_url }} | The creative as an image — the picture of an image ad or the thumbnail of a video ad; null when Meta sends none |
    | {{ $json.data.referral.ref }} | Your own marker from the ref parameter of an m.me / ig.me link or an Instagram / Messenger ad. Always null on WhatsApp |
    | {{ $json.data.referral.raw }} | Meta’s referral object exactly as received — ad id, ctwaclid (WhatsApp, for the Conversions API), welcomemessage, … Field names differ per channel |

    text and image_url are meant to go straight into an AI Agent prompt: the user is replying to an ad that said this and looked like this.

    A returning user — conversation.referral (Instagram, Messenger). When someone who already has a conversation with you clicks an ad or an m.me / ig.me link without writing, Meta sends the attribution as a separate event with no message: data.from, data.from_name and the same data.referral block. The click reopens the 24-hour window, so you may reply. Select Conversation Referral in the trigger’s Event Types to receive it. WhatsApp has no equivalent — there the attribution always arrives with a message.

    What to expect:

  • One-shot. The block is on the event that follows the click and is not repeated on later messages — store it on the conversation when it arrives.
  • Creative links are temporary. image_url and the URLs in raw are public Meta CDN links with an undocumented lifetime; fetch the image when the event arrives if you want to keep it.
  • No referral ≠ organic. Only ads and ref links carry attribution; Meta may also omit raw.ctwa_clid (Status ads, web clicks, a deleted ad).
  • Full contract: Receiving Messages → Referral context.

    type: "unsupported"

    data.type is text, image, audio, video, document, share or unsupported — never a raw provider value, so it is safe to switch on (treat a value you do not know like unsupported). A sticker is an image with data.media.sticker: true. unsupported means Fiwano cannot hand you the content as a file, and data.unsupportedtype says what it was. Two cases, told apart by upgraderequired:

    | Case | Looks like | What to do |
    |—|—|—|
    | Media on a Starter license | unsupportedtype is the media type (image, …) and upgraderequired: "pro" | Upgrade to Pro to receive the file |
    | Content that is not a file | unsupportedtype is Meta’s own name — location, contacts, order, edit, nfmreply, … (WhatsApp); template, ephemeral (Instagram); template, location, appointmentbooking (Facebook) — and no upgraderequired | No tier delivers these as files; handle or ignore |

    There is no data.media block on unsupported. An unfamiliar unsupported_type is still just unsupported content — treat the list as open. Message reactions, edits, deletions and WhatsApp group messages are dropped entirely and never arrive as events. A Messenger link preview never becomes unsupported: the text with the link arrives as text.

    Message echoes (messages sent outside Fiwano)

    When someone on your side answers a customer without going through Fiwano — the WhatsApp Business App, the Instagram inbox, the Facebook Page Inbox, Meta Business Suite, or another integration — Meta echoes that message back, and Fiwano can deliver you a copy so your workflow sees the whole conversation, not just its own half.

    Enable it by selecting Message Echo in the trigger’s Event Types (in auto-setup mode this registers message.echo on the channel). Available on Starter and Pro; on WhatsApp it fires only for Coexistence numbers (a Cloud-API-only channel has no external messages to echo).

    A message.echo event uses the same envelope as every other event; the data block looks like:

    | Expression | Value |
    |—|—|
    | {{ $json.data.message_id }} | A Fiwano UUID, stable across redeliveries — deduplicate on it |
    | {{ $json.data.recipient }} | Who the message was sent to, in the same format the send operations accept — reply to it directly |
    | {{ $json.data.status }} | Always "sent" (the message exists in the conversation; there is no separate message.sent for echoes) |
    | {{ $json.data.type }} | text, image, audio, video, document, share, or unsupported — same values as message.received |
    | {{ $json.data.text }} / {{ $json.data.caption }} | The text, or the caption on a media echo |
    | {{ $json.data.replyto.messageid }} | When the operator replied to a specific customer message — that message’s data.message_id |

    > Never mirror an echo back into the same conversation without deduplicating by message_id. Your own reply generates no echo (Fiwano’s sends are filtered out), but a bot on the other side — or a second integration echoing too — can create a loop.

    Media in echoes is not delivered. An echoed media message keeps its real data.type and caption, but the file is skipped: data.media arrives with downloadurl: null and unavailable: "echomedianotsupported". The rule you already apply to inbound media — check data.media.downloadurl before fetching — covers this with no extra code. Multi-attachment Instagram/Messenger messages split into one echo per attachment, each with its own messageid.

    Not delivered as echoes: reactions, message edits, and message deletions (unsend) — they are changes to an existing message, not new messages, and are silently skipped.

    #### Tracking delivery/read status for echoes

    By default an echo is a one-off copy with no delivered/read follow-ups. To get the same status lifecycle echoes as messages you send through Fiwano, turn on Track Echo Statuses on the channel via Channel → Update (or Exchange OAuth Code) — it maps to the API’s echostatuses. Subsequent message.delivered / message.read / message.failed webhooks then reference the same echo messageid and are filtered by your Event Types exactly like ordinary statuses.

    Statuses and echoes are delivered independently and at-least-once — a status can occasionally arrive before the echo it belongs to. Correlate by message_id and upsert rather than relying on arrival order. WhatsApp/Facebook deliver both delivered and read; Instagram delivers only read (Meta does not provide delivered).

    —

    Sending Messages

    Reading the send result

    All three send operations answer HTTP 200 even when the send fails, and report the
    outcome in the item’s success and status fields:

    | status | success | What it means |
    |—|—|—|
    | sent | true | Meta accepted it. Track the rest via message.delivered / read / failed webhooks. |
    | queued | true | Meta did not give a final answer in time (transient failure, or a slow response — usually a large media download). Fiwano finishes the send in the background, retries transient failures (7 attempts over ~20 min), and emails the channel owner if they run out. Never resend a queued message yourself. Send Template is queued only when Meta answers slowly; a template is never retried or resent. |
    | failed | false | Not sent, and Fiwano will not retry it. error carries Meta’s text and error_code Meta’s code. For Send Text and Send Media the channel owner also receives a delivery digest email. |

    message_id is a Fiwano UUID, not a Meta ID. Every later delivery-status webhook
    references that same UUID.

    #### Error on Failed Send

    What happens on failed is controlled by the Error on Failed Send option on the
    three send operations:

  • On (default on node version 2 — what you get when adding a Fiwano node): the node fails with
  • Send failed: (Meta error ) and a hint on what to do. Handle it
    like any other node error — with **Settings → On Error → "Continue (using error
    output)"** the failed send lands on the node's error output as an item made of your
    input fields plus an error object: error.message, error.hint,
    error.metaerror (Meta's own text), error.errorcode, error.status,
    error.message_id, error.success: false. Branch on it directly, e.g.
    IF {{ $json.error.error_code }} is equal to 131047 → Send Template. (Other node
    errors, such as an empty recipient or an HTTP 400, keep error as a plain string.)

  • Off (default on node version 1): the failed send comes back as a normal item with
  • success: false and the node stays green.
    Branch on it yourself:

      IF  {{ $json.success }}  is false   → your failure path
      

    A note in the output pane reminds you of this before a run, and after a run tells you
    how many sends were rejected. **With the option off, "Continue (using error output)"
    does not catch rejected sends** — n8n routes only thrown errors there, and a returned
    item is not an error.

    A node's version is shown in its Settings tab and never changes on its own; the
    option can be switched either way on both versions. A version 1 node moves to version 2
    only by being replaced with a fresh Fiwano node from the palette.

    #### What the failure means

    error_code is Meta's code, passed through unchanged, and the error hint repeats the
    advice from this table:

    | error_code | What it means | What to do |
    |---|---|---|
    | 100 | Meta rejected a parameter (recipient, text, media URL or size) | Read error; check the recipient format, mediaurl, mediatype and file size |
    | 10 | Unrelated causes; the text in error says which: Messenger / Instagram 24-hour window closed, another app controls the conversation, the Page is restricted by Meta, or Meta denies the action for the account | Window: wait for the user to write again. Routing: make Fiwano the Default routing app. Restricted Page: check Account Quality in Meta Business Suite. Otherwise check the account in Meta Business Settings — see Error 10 |
    | 200 | Meta does not allow this account to send — not a token problem, the channel stays connected | Check the account in Meta Business Settings |
    | 190 | Access token expired or revoked | Reconnect the channel |
    | 551 | Messenger / Instagram: this person cannot be messaged now (blocked the Page, closed the chat, never messaged it) | Nothing on your side; only they can lift it. Do not resend automatically |
    | 803 | Meta does not know this recipient | Check the identifier |
    | 131026 | Recipient is not reachable on WhatsApp | Verify the number |
    | 131042 | Payment problem on the WhatsApp Business account (no payment method attached, credit line over its limit, …) — Meta's billing, not your Fiwano subscription | Fix billing for the account in Meta, then resend (see below) |
    | 131047 | Outside the 24h window (WhatsApp) | Switch to Send Template |
    | 131052 | Meta could not download from media_url | URL unreachable, expired signature, or wrong Content-Type — verify the URL works in a fresh request |
    | 131053 | Format/size unsupported, or Meta rate-limited your hosting provider's network | Retry; if persistent, use AWS S3 / GCS / Cloudflare R2 |
    | 131056, 131057 | Send Template: too many messages to this recipient in a short time, or the WhatsApp Business account is in maintenance mode (Send Text / Send Media retry these and come back queued) | Wait, then send again |
    | 132000, 132012 | Send Template: the variables do not match the template | Check the values and their count for each component |
    | 132001 | Send Template: Meta does not have this template approved in this language | Check the template name, language and status (Template → Get Many) |
    | 132015, 132016 | Send Template: Meta paused or disabled the template (low quality) | Check it in WhatsApp Manager, or use another approved template |
    | 133010 | The WhatsApp number is not registered on the WhatsApp Business Platform — the WhatsApp Business App connection was not completed | Reconnect the channel choosing WhatsApp Business App and finish the connection step in the app |

    Codes outside the table are passed through as Meta returns them; the full list is in the
    API documentation.

    131042 and paid WhatsApp replies. Replies inside the 24h window are free for the
    first 1,000 a month per number; Meta bills the replies after that, and every template.
    Without a payment method on the WhatsApp Business account, the free 1,000 still go out,
    and later replies fail with 131042. Send Template returns the error right away as failed. Send Text and
    Send Media come back queued and are retried for ~20 minutes, so fixing billing in that
    time still gets them out; after that the send stops and the channel owner is emailed.
    Meta may also accept a send and report 131042 later — that arrives as a
    message.failed webhook with the code in data.errors. See
    Messaging Costs.

    #### Requests Fiwano refuses before calling Meta

    These are ordinary node errors (HTTP 400/422), independent of the option above:

  • Recipient empty, or without any digit (a common sign of a broken expression —
  • {{ $json.data }} becomes [object Object], a missing field becomes empty), or not a
    numeric PSID/IGSID on a Messenger/Instagram channel → invalid_recipient. The node
    checks the first two cases itself before making the request and tells you to use
    {{ $json.data.from }}. Note that delivery-status events (delivered, read) carry
    data.recipient, not data.from — there is no sender to reply to.

  • Text empty or whitespace-only → 422; over the channel limit → texttoolong.
  • A WhatsApp send to the channel's own number → recipientequalssender.
  • Text message

    Resource: Message → Operation: Send Text
    Channel ID: 
    Recipient: {{ $('Fiwano Trigger').item.json.data.from }}
    Text: Hello!
    

    Per-channel length caps are WhatsApp 4096, Facebook 2000, Instagram 1000, and Fiwano does not auto-split. Empty text and invalid recipients are refused before Meta is called — see Requests Fiwano refuses before calling Meta.

    Sends are limited to 10 accepted sends per second per channel, shared across all API keys; every other operation is limited to 20 requests per second per API key. Exceeding either returns HTTP 429 with Retry-After, which the node surfaces in the error description.

    WhatsApp template

    Outside the 24-hour conversation window, WhatsApp requires pre-approved templates.

    Resource: Message → Operation: Send Template
    Channel ID: channelid>
    Recipient: withoutplus>
    Template Name: order_confirmation
    Language: en_US
    Variables: {"body": ["John", "ORD-456"]}
    

    Variable format:

  • Positional (numbered {{1}}, {{2}}): {"body": ["val1", "val2"], "header": ["val"], "buttons": [{"index": 0, "value": "abc"}]}
  • Named (custom keys): {"body": {"customer_name": "John"}}
  • Leave empty if the template has no variables
  • Media message (image, audio, video, document)

    Send a media file via HTTPS URL. Requires a Pro license on the channel's billing plan.

    Resource: Message → Operation: Send Media
    Channel ID: 
    Recipient: {{ $('Fiwano Trigger').item.json.data.from }}
    Media Type: image
    Media URL: https://my-bucket.s3.amazonaws.com/photo.jpg?X-Amz-Signature=...
    Additional Fields → Caption: Check this out!
    

    Meta fetches the file directly from Media URL — Fiwano does not download or store it.

    For non-public content, use a signed URL — S3/GCS/R2 presigned, Azure SAS, or HMAC-signed URL on your own server. Set expiry to ≥ 20 minutes so background retries can still fetch the file. Public URLs are accessible to anyone who learns them.

    Send Media is synchronous and can be slow: Meta downloads your file inside the request, so the wait scales with file size and your hosting. Fiwano gives up on Meta after 30 seconds — set your own timeout to at least 35 seconds if you call this from outside n8n.

    URL validation: HTTPS only, max 2048 chars, no credentials in URL (user:pass@), no private/loopback IPs. Violations return HTTP 422.

    Supported types per channel:

    | Media Type | WhatsApp | Instagram | Facebook |
    |------------|----------|-----------|----------|
    | image | ✓ | ✓ | ✓ |
    | audio | ✓ | ✓ | ✓ |
    | video | ✓ | ✓ | ✓ |
    | document | ✓ | ✓ | ✓ (as file) |
    | sticker | ✓ Media URL = WebP file (512×512, ≤100 KB static / ≤500 KB animated) | ✗ | ✓ Sticker ID from Meta's catalog (369239263222822 = thumbs up) or an inbound data.media.sticker_id; no file |

    Stickers. Choose Media Type sticker. On WhatsApp fill Media URL with a WebP;
    on Facebook leave it empty and fill Sticker ID. The wrong field for the channel
    (or any sticker on Instagram) returns HTTP 400 invalidmediarequest before Meta is
    called. Caption and Filename are ignored for stickers.

    Handling errors. A media send that Meta rejects follows the same rules as text —
    see Reading the send result. The media-specific codes are
    131052 (Meta could not download the URL) and 131053 (format/size, or Meta
    rate-limited your hosting provider); 100 also covers a file above the size cap.

    > Channels without a Pro license return HTTP 402. Upgrade at fiwano.com/billing.

    ---

    Enriching Sender Profile (Instagram & Facebook)

    Instagram and Facebook webhooks do not include the sender's name. Use Contact → Get Profile immediately after a Fiwano Trigger to fetch it:

  • Instagram: returns username, name, profilepic, followercount, isverifieduser
  • Facebook: returns firstname, lastname, profile_pic
  • Results are cached 5 minutes on Fiwano's side
  • Not applicable for WhatsApp (name is always present in data.from_name)
  • ---

    Common Patterns

    Reply to same channel and sender:

    channelid: {{ $json.channelid }}
    recipient:  {{ $json.data.from }}
    

    Only process text messages:
    IF → $json.data.type === 'text'

    Get sender name on Instagram/Facebook:
    Add Contact → Get Profile (Channel ID: $json.channel_id, User ID: $json.data.from) immediately after the trigger.

    Filter by channel type:
    IF → $json.channel_type === 'whatsapp'

    ---

    Example Workflows

    Two ready-made flows live in the workflows/ directory. They assemble the pieces above (credential → channel → trigger → send), so you can import one and skip the manual wiring.

    | File | Description |
    |------|-------------|
    | fiwano-connect-channels.json | Connect channels via the API (optional). Only needed if you onboard channels programmatically — e.g. connecting your own clients' channels. If connecting from the Fiwano portal UI is enough for you, you don't need this. Connects one channel at a time: pick a channel type, generate a Meta setup link, and a webhook callback auto-exchanges the returned code for a channel_id — no copy-pasting codes. |
    | fiwano-universal-auto-responder.json | Auto-reply to every message. One trigger answers every message on WhatsApp, Instagram and Facebook — echoes text, and replies to attachments with file details. Includes a sticky recipe for a full media echo. Needs at least one connected channel — connect in the portal, or with the workflow above. |

    Import (works on any n8n, including Cloud): create a new workflow → ⋮ menu → Import from File → select the .json.

    After importing, finish setup before the workflow will run:
    1. Add your Fiwano API credential to the nodes that use it (see Credentials).
    2. For fiwano-connect-channels.json, add the OAuth-callback node's Production URL to your whitelisted redirect URIs (Redirect URI → Add, or in the portal).
    3. Activate the workflow — the trigger and the OAuth-callback webhook only fire while the workflow is active.

    On self-hosted n8n you can also import from the command line, run on the machine where n8n is installed (the --input path is relative to your current directory; the workflow is imported inactive — activate it in the UI afterwards):

    n8n import:workflow --input=workflows/fiwano-universal-auto-responder.json
    

    ---

    Links

  • fiwano.com — product page & free trial
  • API Documentation
  • Fiwano Cookbook — step-by-step guide for integrating the API directly in code (handy for AI coding agents)
  • Portal

License

MIT — see LICENSE