### Install Fiwano via npm Source: https://fiwano.com/documentation/n8n Use this manual installation method for restricted self-hosted n8n environments where in-app installation is unavailable. ```bash mkdir -p ~/.n8n/nodes && cd ~/.n8n/nodes npm install n8n-nodes-fiwano # Restart n8n ``` -------------------------------- ### WhatsApp media audio example Source: https://fiwano.com/documentation/webhooks WhatsApp voice message example (Pro license). The `voice` flag is true for voice messages; use `download_url` to fetch the file before it expires. ```json { "event": "message.received", "channel_id": "a1b2c3d4e5f67890", "channel_type": "whatsapp", "timestamp": "2025-01-15T10:30:00Z", "data": { "message_id": "wamid.xxx", "from": "1234567890", "from_name": "John Doe", "type": "audio", "media": { "media_id": "m2b3c4d5e6f78901", "voice": true, "mime_type": "audio/ogg; codecs=opus", "file_size": 12345, "filename": null, "sha256": "def456...", "duration_ms": 5200, "download_url": "https://fiwano.com/api/v1/media/m2b3c4d5e6f78901", "expires_at": "2025-01-15T11:30:00Z" } } } ``` -------------------------------- ### WhatsApp media image example Source: https://fiwano.com/documentation/webhooks WhatsApp image message example (Pro license). The media file is downloaded from Meta and stored temporarily; use `download_url` to fetch the file before it expires. ```json { "event": "message.received", "channel_id": "a1b2c3d4e5f67890", "channel_type": "whatsapp", "timestamp": "2025-01-15T10:30:00Z", "data": { "message_id": "wamid.xxx", "from": "1234567890", "from_name": "John Doe", "type": "image", "caption": "Check this photo", "media": { "media_id": "m1b2c3d4e5f67890", "mime_type": "image/jpeg", "file_size": 245760, "filename": null, "sha256": "abc123...", "duration_ms": null, "download_url": "https://fiwano.com/api/v1/media/m1b2c3d4e5f67890", "expires_at": "2025-01-15T11:30:00Z" } } } ``` -------------------------------- ### POST /api/v1/channels/setup-url Source: https://fiwano.com/documentation/quickstart Creates a setup URL for the embedded OAuth flow to connect end-users' channels. ```APIDOC ## POST /api/v1/channels/setup-url ### Description Creates a setup URL for the embedded OAuth flow to connect end-users' channels. ### Method POST ### Endpoint /api/v1/channels/setup-url ### Parameters #### Request Body - **redirect_uri** (string) - Required - The whitelisted redirect URI for the OAuth flow. ### Response #### Success Response (200) Returns a setup URL that the user can be directed to. ``` -------------------------------- ### Request setup URL with POST /api/v1/channels/setup-url Source: https://fiwano.com/documentation/channels Requests a setup URL for a channel by passing a whitelisted redirect URI. The returned URL is valid until `expires_at`. The same endpoint also reconnects channels; if the Meta identity already belongs to an inactive channel, Fiwano reactivates that row and `exchange-code` returns the existing `channel_id`. ```bash curl -X POST https://fiwano.com/api/v1/channels/setup-url \ -H "X-API-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"channel_type": "whatsapp", "redirect_uri": "https://yourapp.com/callback"}' Copy ``` -------------------------------- ### Authenticate with X-API-Key Source: https://fiwano.com/documentation Include your API key in the X-API-Key header for all requests. Keys must start with mip_live_. ```bash curl https://fiwano.com/api/v1/channels \ -H "X-API-Key: YOUR_API_KEY" ``` -------------------------------- ### GET /api/v1/subscriptions Source: https://fiwano.com/documentation/subscriptions Retrieves all subscriptions and aggregate slot availability for each channel type. Use this endpoint when an external service needs to decide whether it can start a new channel connection flow. ```APIDOC ## GET /api/v1/subscriptions ### Description Retrieves all subscriptions and aggregate slot availability for each channel type. Use this endpoint when an external service needs to decide whether it can start a new channel connection flow. ### Method GET ### Endpoint /api/v1/subscriptions ### Parameters #### Headers - **X-API-Key** (string) - Required - API key for authentication. ### Request Example ``` curl -H "X-API-Key: $FIWANO_API_KEY" \ https://fiwano.com/api/v1/subscriptions ``` ### Response #### Success Response (200) - **available_slots** (object) - Aggregate slot availability per channel type. Each channel type has `total`, `starter`, and `pro` fields. - **subscriptions** (array) - List of subscription objects. Each subscription has `id`, `status`, `source`, `tier`, `auto_renew`, and `assigned_channels`. #### Response Example ``` { "available_slots": { "whatsapp": { "total": 0, "starter": 0, "pro": 0 }, "instagram": { "total": 1, "starter": 0, "pro": 1 }, "facebook": { "total": 1, "starter": 0, "pro": 1 } }, "subscriptions": [ { "id": "a1b2c3d4e5f67890", "status": "active", "source": "trial", "tier": "pro", "auto_renew": false, "assigned_channels": { "whatsapp": { "channel_id": "1111222233334444", "channel_type": "whatsapp", "name": "Acme Support", "is_active": false }, "instagram": null, "facebook": null } } ] } ``` ### Notes - Use `available_slots..total > 0` as the signal that a new channel of that type can be connected. - An inactive channel can still occupy a slot because Fiwano preserves the binding for reconnect. - In `available_slots`, `total` is the sum of the currently free `starter` and `pro` slots for that channel type. - In each subscription, `assigned_channels` shows which channel is assigned to the subscription for each type; `null` means no channel is assigned there. - The reverse mapping is on the channel itself: `subscription.id` in `GET /api/v1/channels`. - To move a channel to a different subscription, or to release a slot so another channel of the same type can take it, use `subscription_id` in `PATCH /api/v1/channels/{channel_id}` — see subscription slots. ``` -------------------------------- ### GET /api/v1/redirects Source: https://fiwano.com/documentation/channels Lists the whitelisted redirect URIs for your API key. ```APIDOC ## GET /api/v1/redirects ### Description Returns the list of whitelisted redirect URIs. ### Method GET ### Endpoint https://fiwano.com/api/v1/redirects ### Parameters No parameters documented. ### Response No response schema provided in the source. ``` -------------------------------- ### Create WhatsApp template with curl Source: https://fiwano.com/documentation/templates Creates a UTILITY template named 'order_confirmation' with a BODY component using positional variables. Requires a Pro license and a valid channel ID. The template is submitted to Meta and starts in PENDING status. ```bash curl -X POST https://fiwano.com/api/v1/channels/a1b2c3d4e5f67890/templates \ -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \ -d '{ "name": "order_confirmation", "category": "UTILITY", "language": "en_US", "components": [ {"type": "BODY", "text": "Hi {{1}}, your order {{2}} is confirmed.", "example": {"body_text": [["Pablo", "ORD-123"]]}} ], "parameter_format": "positional" }' ``` -------------------------------- ### WhatsApp message.received text example Source: https://fiwano.com/documentation/webhooks Example of a WhatsApp text message webhook. `data.from` is the sender's phone number without `+`; use it as `recipient` when replying. ```json { "event": "message.received", "channel_id": "a1b2c3d4e5f67890", "channel_type": "whatsapp", "timestamp": "2025-01-15T10:30:00Z", "data": { "message_id": "wamid.xxx", "from": "1234567890", "from_name": "John Doe", "type": "text", "text": "Hello!" } } ``` -------------------------------- ### Empty channels response on fresh account Source: https://fiwano.com/documentation/quickstart Example of the successful response when the API key is valid but there are no channels yet. It serves as the success signal that authentication works. ```json { "channels": [], "total": 0 } ``` -------------------------------- ### Failure redirect with error and message parameters Source: https://fiwano.com/documentation/channels Example failure redirect. The `error` parameter is machine-readable (`access_denied` or `setup_failed`) and should be used for branching; `message` is a URL-encoded, human-readable explanation that may change and must never be parsed or used for branching. ```text https://yourapp.com/callback?error=setup_failed&message=We%20couldn%27t%20access%20any%20Instagram%20Business%20account... Copy ``` -------------------------------- ### GET /api/v1/media/{media_id} Source: https://fiwano.com/documentation/quickstart Downloads received media by its ID. ```APIDOC ## GET /api/v1/media/{media_id} ### Description Downloads received media by its ID. ### Method GET ### Endpoint /api/v1/media/{media_id} ### Parameters #### Path Parameters - **media_id** (string) - Required - The unique identifier of the media. ### Response #### Success Response (200) Returns the media content. ``` -------------------------------- ### GET /api/v1/redirects Source: https://fiwano.com/documentation/quickstart Lists whitelisted redirect URIs for the embedded OAuth flow. ```APIDOC ## GET /api/v1/redirects ### Description Lists whitelisted redirect URIs for the embedded OAuth flow. ### Method GET ### Endpoint /api/v1/redirects ### Response #### Success Response (200) Returns a list of redirect URIs. ``` -------------------------------- ### GET /api/v1/channels Source: https://fiwano.com/documentation/quickstart Lists all channels associated with the authenticated account. Used to verify the API key and to check the status of connected channels. ```APIDOC ## GET /api/v1/channels ### Description Lists all channels associated with the authenticated account. Used to verify the API key and to check the status of connected channels. ### Method GET ### Endpoint /api/v1/channels ### Parameters #### Headers - **X-API-Key** (string) - Required - Your API key, e.g., `mip_live_...` ### Response #### Success Response (200) - **channels** (array) - List of channel objects - **total** (integer) - Total number of channels #### Response Example { "channels": [], "total": 0 } #### Error Response (401) Invalid or missing API key. ``` -------------------------------- ### message.received unsupported type (Starter license) Source: https://fiwano.com/documentation/webhooks Example webhook payload for a message.received event with type "unsupported" when the media file exists but the current license tier does not include it. The unsupported_type indicates the media type Pro would have delivered, and upgrade_required names the tier that unlocks it. Upgrade via the Billing page in the portal to receive full media content. ```json { "event": "message.received", "channel_id": "a1b2c3d4e5f67890", "channel_type": "whatsapp", "timestamp": "2025-01-15T10:30:00Z", "data": { "message_id": "wamid.xxx", "from": "1234567890", "from_name": "John Doe", "type": "unsupported", "unsupported_type": "image", "upgrade_required": "pro" } } ``` -------------------------------- ### Instagram message.received text example Source: https://fiwano.com/documentation/webhooks Example of an Instagram text message webhook. `data.from` is the IGSID; use it as `recipient` when replying. `from_name` is always `null` because Meta does not include sender name in IG webhooks. ```json { "event": "message.received", "channel_id": "b2c3d4e5f6789012", "channel_type": "instagram", "timestamp": "2025-01-15T10:30:00Z", "data": { "message_id": "mid.xxx", "from": "6543217890123456", "from_name": null, "type": "text", "text": "Hi there!" } } ``` -------------------------------- ### Success redirect with code parameter Source: https://fiwano.com/documentation/channels Example success redirect after the user completes Meta OAuth. The one-time `code` parameter is used in the subsequent exchange-code call. On failure, the redirect instead carries `error` and `message` query parameters; branch logic on `error` only. ```text https://yourapp.com/callback?code=abc123... Copy ``` -------------------------------- ### Facebook Messenger message.received text example Source: https://fiwano.com/documentation/webhooks Example of a Facebook Messenger text message webhook. `data.from` is the PSID; use it as `recipient` when replying. `from_name` is always `null` because Meta does not include sender name in FB webhooks. ```json { "event": "message.received", "channel_id": "c3f8a1b2e4d56789", "channel_type": "facebook", "timestamp": "2025-01-15T10:30:00Z", "data": { "message_id": "mid.xxx", "from": "7890123456789012", "from_name": null, "type": "text", "text": "Hello from Messenger!" } } ``` -------------------------------- ### message.echo webhook payload for media message Source: https://fiwano.com/documentation/webhooks Example of a message.echo webhook payload for a media message. The media file is not delivered; data.media has null download_url and unavailable set to 'echo_media_not_supported'. Check media.download_url before fetching to handle this case. ```json { "data": { "message_id": "550e8400-e29b-41d4-a716-446655440000", "recipient": "6543217890123456", "status": "sent", "type": "image", "caption": "Invoice photo", "media": {"media_id": null, "download_url": null, "unavailable": "echo_media_not_supported", "kind": "image"} } } ``` -------------------------------- ### GET /api/v1/channels/{channel_id} Source: https://fiwano.com/documentation/quickstart Retrieves details of a specific channel by its ID. ```APIDOC ## GET /api/v1/channels/{channel_id} ### Description Retrieves details of a specific channel by its ID. ### Method GET ### Endpoint /api/v1/channels/{channel_id} ### Parameters #### Path Parameters - **channel_id** (string) - Required - The unique identifier of the channel. ### Response #### Success Response (200) Returns the channel object with its details. ``` -------------------------------- ### GET /api/v1/subscriptions Source: https://fiwano.com/documentation/api Retrieves a list of all active subscriptions for the authenticated account. ```APIDOC ## GET /api/v1/subscriptions ### Description List all subscriptions associated with the account. ### Method GET ### Endpoint https://fiwano.com/api/v1/subscriptions ``` -------------------------------- ### Template send response Source: https://fiwano.com/documentation/sending-messages Example JSON response from a template send. The message_id is a Fiwano UUID used to correlate delivery webhooks. ```json { "success": true, "message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "error": null, "error_code": null, "status": "sent" } ``` -------------------------------- ### GET /api/v1/channels/{channel_id}/profile/{user_id} Source: https://fiwano.com/documentation/webhooks Retrieves profile information for a user on a specific channel. Use this endpoint to get the sender's name and avatar for Instagram and Facebook messages, as the sender's name is not included in webhooks for these channels. ```APIDOC ## GET /api/v1/channels/{channel_id}/profile/{user_id} ### Description Retrieves the profile information for a user on a specific channel. Use this endpoint to get the sender's name and avatar for Instagram and Facebook messages, as the sender's name is not included in webhooks for these channels. ### Method GET ### Endpoint /api/v1/channels/{channel_id}/profile/{user_id} ### Parameters #### Path Parameters - **channel_id** (string) - Required - The ID of the channel (e.g., Instagram or Facebook channel). - **user_id** (string) - Required - The user ID from the webhook's `data.from` value (IGSID for Instagram, PSID for Facebook). ### Response #### Success Response (200) - **username** (string) - Instagram username (Instagram only). - **name** (string) - Display name (Instagram) or first name (Facebook). - **profile_pic** (string) - URL to the profile picture (when available). - **follower_count** (integer) - Number of followers (Instagram only). - **is_verified_user** (boolean) - Whether the user is verified (Instagram only). - **last_name** (string) - Last name (Facebook, when available). - **cached** (boolean) - Indicates whether the response was served from cache. #### Response Example { "username": "john_doe", "name": "John", "profile_pic": "https://example.com/pic.jpg", "follower_count": 1234, "is_verified_user": false, "cached": false } ``` -------------------------------- ### GET /api/v1/channels/{channel_id}/profile/{user_id} Source: https://fiwano.com/documentation/quickstart Looks up the profile of a user (sender) on a specific channel. ```APIDOC ## GET /api/v1/channels/{channel_id}/profile/{user_id} ### Description Looks up the profile of a user (sender) on a specific channel. ### Method GET ### Endpoint /api/v1/channels/{channel_id}/profile/{user_id} ### Parameters #### Path Parameters - **channel_id** (string) - Required - The unique identifier of the channel. - **user_id** (string) - Required - The user's ID (phone number, IGSID, or PSID). ### Response #### Success Response (200) Returns the user's profile information. ``` -------------------------------- ### GET profile endpoint for Instagram/Facebook sender info Source: https://fiwano.com/documentation/webhooks Endpoint to fetch a sender's profile for Instagram and Facebook. Pass the data.from value (IGSID for Instagram, PSID for Facebook) as user_id. Returns username, name, profile_pic, follower_count, and is_verified_user for Instagram; first_name, last_name, and profile_pic for Facebook. Results are cached for 5 minutes. ```http GET /api/v1/channels/{channel_id}/profile/{user_id} ``` -------------------------------- ### message.delivered / message.read webhook payload Source: https://fiwano.com/documentation/webhooks Example webhook payload for message.delivered and message.read events. The same format applies to all channels and all statuses (sent, delivered, read). The message_id is the UUID from the send response. ```json { "event": "message.read", "channel_id": "b2c3d4e5f6789012", "channel_type": "instagram", "timestamp": "2025-01-15T10:30:10Z", "data": { "message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "status": "read", "recipient": "6543217890123456" } } ``` -------------------------------- ### message.failed webhook payload (WhatsApp) Source: https://fiwano.com/documentation/webhooks Example webhook payload for the message.failed event (WhatsApp). Includes error details in the errors array with code 131047 and title 'Message undeliverable'. ```json { "event": "message.failed", "channel_id": "a1b2c3d4e5f67890", "channel_type": "whatsapp", "timestamp": "2025-01-15T10:30:05Z", "data": { "message_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "recipient": "1234567890", "status": "failed", "error": "Message undeliverable", "errors": [{"code": 131047, "title": "Message undeliverable"}] } } ``` -------------------------------- ### Inbound message.webhook payload structure with channel_id and data.from Source: https://fiwano.com/documentation/quickstart Example of a message.received event payload that your webhook endpoint receives. It contains the channel_id of the channel that received the message and data.from which is the sender's identifier to use as the recipient when replying. ```json { "event": "message.received", "channel_id": "a1b2c3d4e5f67890", // ← which of your channels received it "channel_type": "whatsapp", "timestamp": "2025-01-15T10:30:00Z", "data": { "message_id": "wamid.xxx", "from": "1234567890", // ← who sent it — reply to this "from_name": "John Doe", "type": "text", "text": "Hello!" } } ``` -------------------------------- ### message.echo webhook payload for text message Source: https://fiwano.com/documentation/webhooks Example of a message.echo webhook payload for a text message sent outside Fiwano. The message_id is stable for deduplication, and recipient is in the same format as send endpoints accept. Status is 'sent' and no separate message.sent event is emitted for echoes. ```json { "event": "message.echo", "channel_id": "b2c3d4e5f6789012", "channel_type": "instagram", "timestamp": "2026-09-01T10:30:00Z", "data": { "message_id": "550e8400-e29b-41d4-a716-446655440000", "recipient": "6543217890123456", "status": "sent", "type": "text", "text": "Operator reply" } } ``` -------------------------------- ### List channels with curl using X-API-Key header Source: https://fiwano.com/documentation/quickstart Use this curl command to verify your API key works by listing your channels. A valid key on a fresh account returns 200 with an empty list; an invalid or missing key returns 401. ```bash curl https://fiwano.com/api/v1/channels -H "X-API-Key: $FIWANO_API_KEY" ``` -------------------------------- ### Send a media message with curl Source: https://fiwano.com/documentation/sending-messages Use this curl command to send a media message via POST /api/v1/messages/send-media. Requires a Pro license. 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 with expiry ≥ 20 min. Check success and status; permanent failures include Meta error_code (e.g., 131052). Recoverable failures return queued. ```bash 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" }' ``` -------------------------------- ### Template lifecycle diagram Source: https://fiwano.com/documentation/templates Shows the lifecycle of a WhatsApp template: Create leads to PENDING (Meta review, ~24h), then either APPROVED (sendable) or REJECTED (fix & resubmit). ```text Create → PENDING (Meta review, ~24h) → APPROVED (sendable) → REJECTED (fix & resubmit) ``` -------------------------------- ### Replace a channel with a single subscription Source: https://fiwano.com/documentation/channels This workflow outlines the steps to replace an existing channel by deactivating it, freeing its subscription slot, and connecting a new Meta account. ```text GET /api/v1/subscriptions → find the subscription and its occupied slot DELETE /api/v1/channels/{old_id} → deactivate the channel you are replacing PATCH /api/v1/channels/{old_id} → {"subscription_id": ""} frees the slot POST /api/v1/channels/setup-url → user connects the new Meta account POST /api/v1/channels/exchange-code → new channel takes the free slot ``` -------------------------------- ### Download inbound media with curl Source: https://fiwano.com/documentation/webhooks Downloads inbound media using the authenticated download URL. Requires your X-API-Key header. The response is raw file bytes with the original Content-Type and a Content-Disposition filename when known. Files expire about 60 minutes after Fiwano retrieves them from Meta; after expiry the URL returns 410 Gone. ```bash curl https://fiwano.com/api/v1/media/m1b2c3d4e5f67890 \ -H "X-API-Key: YOUR_API_KEY" \ --output photo.jpg ``` -------------------------------- ### Send template message with positional variables Source: https://fiwano.com/documentation/sending-messages Use this curl command to send a WhatsApp template with positional variables ({{1}}, {{2}}). Requires a Pro account and an APPROVED template. The variables object uses arrays for header, body, and buttons. ```bash 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"}] } }' ``` -------------------------------- ### Check subscription status and slot availability Source: https://fiwano.com/documentation/subscriptions Use this curl command to retrieve all subscriptions and aggregate slot availability for channel connections. ```bash curl -H "X-API-Key: $FIWANO_API_KEY" \ https://fiwano.com/api/v1/subscriptions ``` -------------------------------- ### Whitelist redirect URI with POST /api/v1/redirects Source: https://fiwano.com/documentation/channels Registers a redirect URI pattern for OAuth callbacks. The URI must use HTTPS, cannot target localhost or loopback, and may include explicit ports 1-65535. Wildcards are allowed only as a complete left-most hostname label or in the path/query; embedded credentials, fragments, and reserved query keys (`code`, `status`, `channel_type`, `error`) are rejected. ```bash curl -X POST https://fiwano.com/api/v1/redirects \ -H "X-API-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"uri_pattern": "https://yourapp.com/callback"}' Copy ``` -------------------------------- ### Send a text message with curl Source: https://fiwano.com/documentation/sending-messages Use this curl command to send a plain text message via POST /api/v1/messages/send. Works on all channel types. Requires a WhatsApp channel_id and recipient phone number. Authenticate with your Fiwano X-API-Key; no separate Meta key needed. Text length caps: WhatsApp 4096, Facebook 2000, Instagram 1000; oversize text returns 400 text_too_long. Empty or whitespace-only text returns 422. Recipient is trimmed and validated; invalid values return 400 invalid_recipient. ```bash 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."}' ``` -------------------------------- ### POST /api/v1/redirects Source: https://fiwano.com/documentation/quickstart Adds a redirect URI to the whitelist for the embedded OAuth flow. ```APIDOC ## POST /api/v1/redirects ### Description Adds a redirect URI to the whitelist for the embedded OAuth flow. ### Method POST ### Endpoint /api/v1/redirects ### Parameters #### Request Body - **redirect_uri** (string) - Required - The redirect URI to whitelist. ### Response #### Success Response (200) Confirmation of addition. ``` -------------------------------- ### Send template message with named variables Source: https://fiwano.com/documentation/sending-messages Use this curl command to send a WhatsApp template with named variables ({{customer_name}}). The variables object uses an object for the body component. ```bash -d '{ "channel_id": "a1b2c3d4e5f67890", "template_name": "welcome_message", "language": "en_US", "recipient": "1234567890", "variables": {"body": {"customer_name": "Pablo", "order_number": "ORD-123"}} }' ``` -------------------------------- ### POST [webhook_url] Source: https://fiwano.com/documentation/webhooks Fiwano delivers incoming messages and delivery statuses to your configured webhook_url as a POST request. The payload is normalized across all channels, and the request is signed with an X-Webhook-Signature header when a webhook_secret is set. ```APIDOC ## POST [webhook_url] ### Description Fiwano delivers incoming messages and delivery statuses to your channel's webhook_url as a POST request. The payload format is normalized across all channels, and the request is signed with an X-Webhook-Signature header when a webhook_secret is configured. ### Method POST ### Endpoint [webhook_url] (the URL you configured when connecting the channel) ### Headers - **X-Webhook-Signature** (string) - Required if webhook_secret is set - Format: `sha256=`. Used to verify the request came from Fiwano. ### Request Body - **event** (string) - Required - The webhook event type (e.g., `message.received`, `message.sent`, `message.delivered`, `message.read`, `message.failed`, `message.echo`). - **channel_id** (string) - Required - Identifier of the connected channel. - **channel_type** (string) - Required - Type of the channel (e.g., WhatsApp, Instagram, Facebook Messenger). - **timestamp** (string) - Required - Timestamp of the event. - **data** (object) - Required - Event-specific payload. Contains `from` (sender identifier: phone number for WhatsApp, IGSID for Instagram, PSID for Messenger) and `recipient` (user identifier) for status events. ### Request Example ```json { "event": "message.received", "channel_id": "ch_123", "channel_type": "whatsapp", "timestamp": "2025-01-01T12:00:00Z", "data": { "from": "15551234567", "message": { "type": "text", "text": "Hello" } } } ``` ### Response #### Success Response (200) - **status** (string) - Description: Acknowledgment of receipt. (Exact response body not specified in source.) #### Response Example ```json { "status": "ok" } ``` ### Error Handling - If the signature verification fails, the request should be rejected. (No specific error codes provided.) ### Notes - Only events explicitly enabled via `webhook_events` are delivered. By default, no events are enabled. - The top-level fields (`event`, `channel_id`, `channel_type`, `timestamp`, `data`) are stable across all channels. - Status progression: `sent → delivered → read`. Each status implies all previous ones. - Statuses can arrive out of order; treat the highest status seen as current and upsert by `message_id`. - For `message.read`, Fiwano sends a separate webhook for each unread message (read cascading). - `message.read` may not arrive if the recipient has disabled read receipts; treat `delivered` as terminal success. ``` -------------------------------- ### Unified Webhook Event Structure Source: https://fiwano.com/documentation/unifying-delivery-statuses The standardized JSON envelope format for all delivery status events received at the configured webhook_url, regardless of the underlying channel. ```json { "event": "message.delivered", "channel_id": 42, "channel_type": "instagram", "timestamp": "2026-06-25T10:00:05Z", "data": { "message_id": "a1b2c3d4-...", "status": "delivered", "recipient": "..." } } ``` -------------------------------- ### Multiple attachments ID pattern Source: https://fiwano.com/documentation/webhooks Shows how multiple attachments are delivered: each attachment is its own webhook and HTTP POST. The first event keeps Meta's message ID and carries the caption; later events use deterministic IDs with `.2`, `.3`, etc., and omit the caption. ```text mid.xxx image + caption mid.xxx.2 image mid.xxx.3 video ``` -------------------------------- ### Subscription API response structure Source: https://fiwano.com/documentation/subscriptions The JSON response contains available_slots for each channel type and a list of active subscriptions with their assigned channels. ```json { "available_slots": { "whatsapp": { "total": 0, "starter": 0, "pro": 0 }, "instagram": { "total": 1, "starter": 0, "pro": 1 }, "facebook": { "total": 1, "starter": 0, "pro": 1 } }, "subscriptions": [ { "id": "a1b2c3d4e5f67890", "status": "active", "source": "trial", "tier": "pro", "auto_renew": false, "assigned_channels": { "whatsapp": { "channel_id": "1111222233334444", "channel_type": "whatsapp", "name": "Acme Support", "is_active": false }, "instagram": null, "facebook": null } } ] } ``` -------------------------------- ### Subscription object structure Source: https://fiwano.com/documentation/subscriptions The JSON structure returned within a channel object representing its current billing state. ```json "subscription": { "status": "active", "source": "paddle", "tier": "pro", "expires_at": "2025-02-15T10:30:00", "auto_renew": true } ``` -------------------------------- ### Verifying webhook signature with Python (HMAC-SHA256) Source: https://fiwano.com/documentation/webhooks Python function to verify the webhook signature by computing HMAC-SHA256 of the raw request body using the webhook_secret as key and comparing the hex digest. The header is expected to include the 'sha256=' prefix which is stripped before comparison. This is strongly recommended when a webhook_secret is configured. ```python import hmac, hashlib def verify_signature(body: bytes, secret: str, header: str) -> bool: expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest() received = header.replace("sha256=", "") return hmac.compare_digest(expected, received) ``` -------------------------------- ### Verifying webhook signature header format Source: https://fiwano.com/documentation/webhooks Shows the format of the X-Webhook-Signature header sent when a webhook_secret is configured. The header contains an HMAC-SHA256 hex digest. This header is absent when no secret is set. ```text X-Webhook-Signature: sha256= ``` -------------------------------- ### Standard Error Response Source: https://fiwano.com/documentation Most domain errors return a JSON object containing a detail field with a human-readable description. ```json { "detail": "Human-readable error description" } ``` -------------------------------- ### PATCH /api/v1/channels/{channel_id} Source: https://fiwano.com/documentation/quickstart Updates a channel's configuration, such as setting or updating `webhook_events` and `webhook_url`. ```APIDOC ## PATCH /api/v1/channels/{channel_id} ### Description Updates a channel's configuration, such as setting or updating `webhook_events` and `webhook_url`. ### Method PATCH ### Endpoint /api/v1/channels/{channel_id} ### Parameters #### Path Parameters - **channel_id** (string) - Required - The unique identifier of the channel. #### Request Body - **webhook_events** (array) - Optional - List of event types to enable, e.g., `["message.received"]`. - **webhook_url** (string) - Optional - The URL where webhooks will be sent. ### Response #### Success Response (200) Returns the updated channel object. ``` -------------------------------- ### Send a free-form reply via curl Source: https://fiwano.com/documentation/quickstart Use this curl command to reply to a user within the 24-hour window. It sends a text message using the webhook's channel_id as channel_id and data.from as recipient. The API key is required in the header. On success, it returns a message_id and triggers message.sent/message.delivered webhooks if enabled. ```curl 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": "Thanks for your message!"}' ``` -------------------------------- ### DELETE /api/v1/redirects/{redirect_id} Source: https://fiwano.com/documentation/quickstart Removes a redirect URI from the whitelist. ```APIDOC ## DELETE /api/v1/redirects/{redirect_id} ### Description Removes a redirect URI from the whitelist. ### Method DELETE ### Endpoint /api/v1/redirects/{redirect_id} ### Parameters #### Path Parameters - **redirect_id** (string) - Required - The unique identifier of the redirect URI. ### Response #### Success Response (200) Confirmation of deletion. ``` -------------------------------- ### Common payload structure Source: https://fiwano.com/documentation/webhooks Shows the common top-level structure for all webhook payloads. The `data` field varies by event type. ```json { "event": "message.received", "channel_id": "a1b2c3d4e5f67890", "channel_type": "whatsapp", "timestamp": "2025-01-15T10:30:00Z", "data": { ... } } ``` -------------------------------- ### POST /api/v1/channels/exchange-code Source: https://fiwano.com/documentation/quickstart Exchanges a one-time code from the OAuth flow for a `channel_id`. ```APIDOC ## POST /api/v1/channels/exchange-code ### Description Exchanges a one-time code from the OAuth flow for a `channel_id`. ### Method POST ### Endpoint /api/v1/channels/exchange-code ### Parameters #### Request Body - **code** (string) - Required - The one-time code returned after the user completes Meta login. ### Response #### Success Response (200) Returns the `channel_id` of the connected channel. ``` -------------------------------- ### Exchange code with POST /api/v1/channels/exchange-code Source: https://fiwano.com/documentation/channels Exchanges the one-time code for a channel within 5 minutes. The response returns `channel_id` (store it) and, when `webhook_url` is set without `webhook_secret`, auto-generates a secret returned only in this response. All fields except `code` are optional and can be updated later via `PATCH /api/v1/channels/{id}`. ```bash curl -X POST https://fiwano.com/api/v1/channels/exchange-code \ -H "X-API-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "abc123...", "webhook_url": "https://yourapp.com/webhooks/meta", "webhook_events": ["message.received", "message.delivered", "message.failed"] }' Copy ``` -------------------------------- ### DELETE /api/v1/channels/{channel_id} Source: https://fiwano.com/documentation/quickstart Deletes a channel by its ID. ```APIDOC ## DELETE /api/v1/channels/{channel_id} ### Description Deletes a channel by its ID. ### Method DELETE ### Endpoint /api/v1/channels/{channel_id} ### Parameters #### Path Parameters - **channel_id** (string) - Required - The unique identifier of the channel. ### Response #### Success Response (200) Confirmation of deletion. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.