Skip to main content

Facebook Messenger Connector

Send and receive messages through the Facebook Messenger Platform API using a Facebook Page.

Package

dotnet add package Ratatosk.Facebook

Required settings

ParameterTypeDescription
PageAccessTokenstringLong-lived Facebook Page access token (starts with EAA)
PageIdstringFacebook Page ID (numeric)

Optional settings

ParameterTypeDescription
WebhookUrlstringURL for receiving Messenger webhook events
VerifyTokenstringToken used for webhook verification challenge

The PageAccessToken must be a long-lived token (valid ~60 days). Generate it from Facebook Developer Console → Your App → Messenger → Settings → Page Access Token.

Schema

PropertyValue
ProviderFacebook
TypeMessenger
Version1.0.0
CapabilitiesSendMessages, ReceiveMessages, MediaAttachments, InteractiveContent
Content typesPlainText, Media, Json, Button, QuickReply, Carousel, ListPicker
EndpointsUserId (PSID), Id (page-scoped ID)
AuthenticationAPI Key (PageAccessToken)

Send examples

Text message

var settings = new ConnectionSettings()
.SetParameter("PageAccessToken", "EAA...")
.SetParameter("PageId", "1234567890");

var connector = new FacebookMessengerConnector(settings);
await connector.InitializeAsync(ct);

var message = new MessageBuilder()
.WithId("fb-1")
.To(Endpoint.User("facebook-user-psid"))
.WithText("Hello from Facebook Messenger")
.WithMessagingType("RESPONSE")
.Build();

var result = await connector.SendMessageAsync(message, ct);

Message with media (image)

new MessageBuilder()
.To(Endpoint.User("psid-123"))
.WithContent(new MediaContent(MediaType.Image, "photo.jpg",
"https://example.com/photo.jpg"))
.Build();

Message with quick replies

new MessageBuilder()
.To(Endpoint.User("psid-123"))
.WithText("Choose an option:")
.WithQuickReplies("[{\"content_type\":\"text\",\"title\":\"Yes\",\"payload\":\"YES\"},{\"content_type\":\"text\",\"title\":\"No\",\"payload\":\"NO\"}]")
.Build();

Message with buttons

// Using the convenience method
new MessageBuilder()
.To(Endpoint.User("psid-123"))
.WithButton("Open Website", ButtonType.Url, "https://example.com")
.Build();

Message with quick reply options

// Single quick reply option
new MessageBuilder()
.To(Endpoint.User("psid-123"))
.WithQuickReply("Yes", "YES_PAYLOAD")
.Build();
// Using the sub-builder API
new MessageBuilder()
.To(Endpoint.User("psid-123"))
.WithCarousel(carousel => carousel
.AddCard("https://example.com/img1.jpg", "Product A", "Amazing", card =>
card.WithButton("Buy", ButtonType.Postback, "BUY_A")
.WithButton("Details", ButtonType.Url, "https://example.com/a"))
.AddCard("https://example.com/img2.jpg", "Product B", "Even better", card =>
card.WithButton("Buy", ButtonType.Postback, "BUY_B")
.WithButton("Details", ButtonType.Url, "https://example.com/b")))
.Build();

Message with list picker

// Using the sub-builder API
new MessageBuilder()
.To(Endpoint.User("psid-123"))
.WithListPicker(list => list
.WithStyle(ListPickerStyle.Compact)
.AddItem("Pizza", "Delicious cheese pizza")
.AddItem("Burger", "Juicy beef burger"))
.Build();

Webhook setup

Facebook Messenger uses webhooks for inbound messages and delivery events.

1. Configure webhook in Facebook Developer Console

  • Go to your App → Messenger → Settings
  • Set the callback URL to your endpoint
  • Set a verify token (must match the one in your settings)

2. Handle verification challenge

Facebook sends a GET request with hub.mode, hub.verify_token, and hub.challenge parameters. The connector handles this automatically via ReceiveMessagesAsync.

3. Process inbound messages

[HttpGet("/webhooks/facebook")]
[HttpPost("/webhooks/facebook")]
public async Task<IActionResult> FacebookWebhook(CancellationToken ct)
{
if (Request.Method == "GET")
{
// Verification challenge — handled by the connector
using var reader = new StreamReader(Request.Body);
var query = Request.QueryString.Value!;
var source = MessageSource.UrlPost(query);
var result = await _connector.ReceiveMessagesAsync(source, ct);
return Content(result.Data?.Messages.FirstOrDefault()?.Id ?? "error");
}

// Inbound message
using var postReader = new StreamReader(Request.Body);
var body = await postReader.ReadToEndAsync(ct);
var msgSource = MessageSource.Json(body);

// Verify signature
var signature = Request.Headers["X-Hub-Signature-256"].FirstOrDefault();
if (!IsValidSignature(body, signature))
return Unauthorized();

var result = await _connector.ReceiveMessagesAsync(msgSource, ct);
return Ok();
}

Validate X-Hub-Signature-256 header using your Facebook app secret before processing.

Error codes

Facebook-specific error codes are defined in FacebookErrorCodes with domain "Facebook".

CodeDescription
INVALID_ACCESS_TOKENPage Access Token is invalid or expired
MISSING_PAGE_IDPage ID is required but not configured
INVALID_PAGE_IDPage ID does not exist or token lacks permission
CONNECTION_TEST_FAILEDConnection test to Graph API failed
GRAPH_API_ERRORFacebook Graph API returned an error
OPERATION_NOT_SUPPORTEDOperation not available for the current Page or API version

Standard MessagingErrorCodes are also used — see the error codes reference.

Original provider codes

Facebook errors are assigned directly via ConnectorException without mapping from Graph API error codes. The Graph API returns its own error objects (e.g., {"error": {"message": "...", "type": "OAuthException", "code": 190}}) which are surfaced through the GRAPH_API_ERROR code.

Troubleshooting

SymptomLikely causeFix
INVALID_CREDENTIALSToken expired or invalidRegenerate long-lived token (valid ~60 days)
INVALID_RECIPIENTPSID doesn't exist or page can't message userUser must have interacted with the page
Webhook verification failsVerifyToken mismatchEnsure VerifyToken matches Facebook Console
Message not deliveredUser blocked the pageRemove user from your store
RATE_LIMITEDToo many messagesFacebook limits: 250 messages per page per hour (standard)