Portal Community

Messenger Interactive Elements

ElementPayload limitBest for
Postback button (in Generic Template)1000 charsStructured approval with field context shown as a card
Quick Reply1000 charsSimple approve/reject after a text message
URL Buttonn/aOpening a web form — useful for editable fields

Correlation Strategy: Direct Embed

Messenger button payload fields support 1000 characters — enough to embed a prefixed GUID directly:

"payload": "HIL_APPROVE|3fa85f64-5717-4562-b3fc-2c963f66afa6"
"payload": "HIL_REJECT|3fa85f64-5717-4562-b3fc-2c963f66afa6"

Building the Message

Use a Generic Template to display the HIL fields and provide buttons:

private object BuildMessengerMessage(
    IReadOnlyList<ResolvedHilField> fields,
    string resId,
    string recipientPsid)
{
    var subtitleLines = new List<string>();
    foreach (var field in fields)
    {
        if (field.DisplayMode == HilDisplayMode.Concealed) continue;
        string val = field.DisplayMode == HilDisplayMode.ReadableMasked
            ? "••••••••"
            : field.CurrentValue?.ToString() ?? "—";
        subtitleLines.Add($"{field.Label}: {val}");
    }

    return new {
        recipient = new { id = recipientPsid },
        message = new {
            attachment = new {
                type    = "template",
                payload = new {
                    template_type = "generic",
                    elements = new[] {
                        new {
                            title    = "Approval Required",
                            subtitle = string.Join(" | ", subtitleLines.Take(3)), // 80-char limit on subtitle
                            buttons  = new object[] {
                                new {
                                    type    = "postback",
                                    title   = "Approve ✅",
                                    payload = $"HIL_APPROVE|{resId}"
                                },
                                new {
                                    type    = "postback",
                                    title   = "Reject ❌",
                                    payload = $"HIL_REJECT|{resId}"
                                }
                            }
                        }
                    }
                }
            }
        }
    };
}
Subtitle length limit The Generic Template subtitle is limited to 80 characters. For HIL flows with many fields, send a text message listing all the fields first, followed by the template with just the action buttons.

Sending the Message

// POST to https://graph.facebook.com/v19.0/me/messages?access_token={token}
await _httpClient.PostAsJsonAsync(
    $"https://graph.facebook.com/v19.0/me/messages?access_token={settings.PageAccessToken}",
    message,
    cancellationToken);

return NodeExecutionResult.Suspend("waiting");

Webhook Handler

Messenger webhooks deliver postback events with messaging[].postback.payload. The webhook endpoint also receives a GET challenge request during setup — handle both.

// GET: webhook verification challenge
[HttpGet("webhooks/messenger")]
public IActionResult Verify([FromQuery] string hub_mode, [FromQuery] string hub_challenge,
                             [FromQuery] string hub_verify_token)
{
    if (hub_mode == "subscribe" && hub_verify_token == _settings.VerifyToken)
        return Content(hub_challenge);
    return Forbid();
}

// POST: inbound events
[HttpPost("webhooks/messenger")]
public async Task<IActionResult> Handle([FromBody] MessengerWebhookPayload payload)
{
    foreach (var entry in payload.Entry)
    foreach (var messaging in entry.Messaging)
    {
        var postbackPayload = messaging.Postback?.Payload;
        if (postbackPayload == null || !postbackPayload.StartsWith("HIL_")) continue;

        var parts  = postbackPayload.Split('|', 2);
        var action = parts[0];  // "HIL_APPROVE" or "HIL_REJECT"
        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();
}

Handling Editable Fields

For RequiredFromHuman fields, add a URL Button that opens a hosted BizFirst web form pre-populated with the current field values. The form URL includes a signed token carrying the ExecutionResId. On form submission, the web endpoint calls ContinueAsync with the collected values.

{
    "type": "web_url",
    "url":  "https://your-domain/hil/form?token={signedToken}",
    "title": "Edit Values"
}

Required Configuration

Config FieldValue
PageAccessToken@{secret:MessengerPageAccessToken}
WebhookVerifyToken@{secret:MessengerVerifyToken}
RecipientPsid@{input:messengerPsid} — the user's Page-Scoped ID
AppSecret@{secret:MessengerAppSecret} — for request signature validation
24-hour messaging window Like WhatsApp, Messenger restricts proactive outbound messages. You can only send freely within 24 hours of the user's last inbound message. Outside this window, use a Message Tag (e.g., ACCOUNT_UPDATE) or a template — subject to Meta's policy approval.