Portal Community

Instagram vs Facebook Messenger API

AspectFacebook MessengerInstagram
API endpoint/me/messages with Page token/me/messages with Page token connected to Instagram Business Account
User identifierPage-Scoped ID (PSID)Instagram-Scoped User ID (IGSID)
Button templatesFull Generic Template supportedGeneric Template not supported — use quick replies or plain text + postback
Quick repliesSupportedSupported
24-hour windowYesYes
Webhook eventsmessages, messaging_postbacksmessages, messaging_postbacks
No Generic Template on Instagram The card-style Generic Template that works well in Messenger is not available in Instagram DMs. Use Quick Replies for approve/reject flows, or send a text message followed by a list of quick reply options.

Building the Message with Quick Replies

private object BuildInstagramMessage(
    IReadOnlyList<ResolvedHilField> fields,
    string resId,
    string recipientIgsid)
{
    var lines = new List<string> { "📋 *Approval Required*\n" };
    foreach (var field in fields)
    {
        if (field.DisplayMode == HilDisplayMode.Concealed) continue;
        string val = field.DisplayMode == HilDisplayMode.ReadableMasked
            ? "••••••••"
            : field.CurrentValue?.ToString() ?? "—";
        lines.Add($"• {field.Label}: {val}");
    }
    lines.Add("\nPlease select an action:");

    return new {
        recipient = new { id = recipientIgsid },
        message = new {
            text = string.Join("\n", lines),
            quick_replies = new object[] {
                new {
                    content_type = "text",
                    title        = "Approve ✅",
                    payload      = $"HIL_APPROVE|{resId}"
                },
                new {
                    content_type = "text",
                    title        = "Reject ❌",
                    payload      = $"HIL_REJECT|{resId}"
                }
            }
        }
    };
}

Sending the Message

// Identical endpoint to Messenger — same Graph API, different token scope
await _httpClient.PostAsJsonAsync(
    $"https://graph.facebook.com/v19.0/me/messages?access_token={settings.PageAccessToken}",
    message,
    cancellationToken);

return NodeExecutionResult.Suspend("waiting");

Webhook Handler

Instagram quick reply responses arrive as regular messaging events with message.quick_reply.payload. The handler is nearly identical to Messenger.

[HttpPost("webhooks/instagram")]
public async Task<IActionResult> Handle([FromBody] MessengerWebhookPayload payload)
{
    foreach (var entry in payload.Entry)
    foreach (var messaging in entry.Messaging)
    {
        // Quick reply response
        var quickReplyPayload = messaging.Message?.QuickReply?.Payload;
        if (quickReplyPayload != null && quickReplyPayload.StartsWith("HIL_"))
        {
            var parts  = quickReplyPayload.Split('|', 2);
            var action = parts[0];
            var resId  = parts[1];

            var responseData = new Dictionary<string, object>
            {
                ["approved"]    = action == "HIL_APPROVE",
                ["respondedBy"] = messaging.Sender.Id
            };

            _ = Task.Run(() => _continuationOrchestrator.ContinueAsync(resId, responseData));
        }
    }
    return Ok();
}

Sharing the Same Webhook

Meta allows a single webhook URL to receive events from multiple products (Messenger, Instagram, WhatsApp) by subscribing to different object types. You can route all three to the same controller and dispatch by the object type in the payload:

// payload.Object == "instagram"  → Instagram handler
// payload.Object == "page"       → Messenger handler
// payload.Object == "whatsapp_business_account" → WhatsApp handler

Required Permissions

PermissionPurpose
instagram_basicRead Instagram Business Account info
instagram_manage_messagesSend and receive DMs
pages_messagingAccess to the connected Facebook Page for token
pages_read_engagementRequired alongside pages_messaging

Required Configuration

Config FieldValue
PageAccessToken@{secret:InstagramPageAccessToken} — token for the Page connected to the Instagram Business Account
WebhookVerifyToken@{secret:InstagramVerifyToken}
RecipientIgsid@{input:instagramScopedUserId}
Getting the IGSID The Instagram-Scoped User ID (IGSID) is only available after the user has sent your account a message first — it appears in the inbound webhook event's sender.id. You cannot initiate a first contact unless the user has already messaged you within the 24-hour window.