Marketing
Meta (Facebook) Marketing integration — OAuth connect, ad accounts, campaign/adset/ad reads, ad↔product links — and Meta/TikTok pixel server events.
Two marketing surfaces live in the API:
- Meta integration (
store.integrations.meta) — connect a Meta account per store, then read ad accounts, campaigns, ad sets, ads and KPIs, and maintain ad ↔ product links that join ad spend with the Feeef orders those products actually took. - Pixel server events — server-side conversion events to Meta Pixel (Conversions API) and TikTok Pixel (Events API), fanned out to every pixel configured on the store.
Connect a Meta account
The OAuth handshake is store-scoped and authenticated end to end. Tokens are exchanged for a
long-lived (~60 days) token, stored encrypted server-side, and never returned to clients —
config reads expose only an oauth2Connected boolean (see
the config envelope).
POST /v1/stores/{storeId}/integrations/meta/oauth/start — optional body
{ "popup": true, "origin": "…", "callbackScheme": "…" }. Returns { "authUrl": "…" }.
Open authUrl — the merchant consents on facebook.com (scope is ads_read only for now).
Meta redirects to the shared marketing callback, which persists the encrypted token on the
store. Web popups get a postMessage; native apps receive a deep link and fetch the outcome
once via GET /v1/social/meta/oauth-result?nonce=….
GET /v1/stores/{storeId}/integrations/meta now reports active, the connected account,
and capabilities (connected, canRead, canManage, needsReconnect).
Ads endpoints are read-only today: managing delivery status needs the ads_management
scope, which is pending Meta App Review. Check capabilities.canManage before offering write
UI. A 409 with code META_NOT_CONNECTED / META_TOKEN_EXPIRED means connect (or reconnect)
first; 403 META_SCOPE_MISSING means the token lacks ads_read.
Meta integration — at a glance
All routes require a Bearer token plus store-member RBAC (reads: any member; writes: editor/admin/owner).
| Method | Path | Description | Auth |
|---|---|---|---|
GET | /v1/stores/{storeId}/integrations/meta | Connection status + capabilities + ads settings | Bearer |
POST | /v1/stores/{storeId}/integrations/meta/oauth/start | Begin OAuth, returns authUrl | Bearer |
DELETE | /v1/stores/{storeId}/integrations/meta/oauth | Disconnect (drops credentials, keeps ad↔product links) | Bearer |
GET | /v1/stores/{storeId}/integrations/meta/ad-accounts | Ad accounts visible to the connected user | Bearer |
PATCH | /v1/stores/{storeId}/integrations/meta/ads/settings | Chosen ad accounts, default account/window, extra storefront hosts | Bearer |
GET | /v1/stores/{storeId}/integrations/meta/ads/summary | Account-level KPI header | Bearer |
GET | /v1/stores/{storeId}/integrations/meta/ads/campaigns | Campaign list + insights | Bearer |
GET | /v1/stores/{storeId}/integrations/meta/ads/adsets | Ad sets (filter by campaignId) | Bearer |
GET | /v1/stores/{storeId}/integrations/meta/ads/ads | Ads decorated with destination URL, matched product, and that product's Feeef orders in-window | Bearer |
GET | /v1/stores/{storeId}/integrations/meta/ads/ads/{adId} | One ad in full (creative, URLs, KPIs) | Bearer |
GET | /v1/stores/{storeId}/integrations/meta/ads/links | Persisted ad↔product mapping | Bearer |
PATCH | /v1/stores/{storeId}/integrations/meta/ads/links/{linkId} | Manual product override (productId: null returns to auto-resolution) | Bearer |
POST | /v1/stores/{storeId}/integrations/meta/ads/sync-links | Full account sweep — re-extract and re-resolve every ad | Bearer |
List queries share these params: adAccountId (required, act_ prefix optional),
datePreset (e.g. last_7d) or since/until (YYYY-MM-DD; explicit range wins),
effectiveStatus[] (ACTIVE, PAUSED, ARCHIVED, …), q (name search), after (Graph
cursor), limit (1–100).
List campaigns with insights
curl -H "Authorization: Bearer $FEEEF_TOKEN" \
"https://api.feeef.org/v1/stores/{storeId}/integrations/meta/ads/campaigns?adAccountId=act_1234567890&datePreset=last_7d&limit=25"Ad ↔ product links
Feeef extracts each ad's destination URL, matches it to a store product (storefront hosts +
extraStoreHosts from ads settings), and persists the mapping so ad KPIs can sit next to the
product's real order counts. Resolution is lazy per page; POST …/ads/sync-links (body
{ "adAccountId": "act_…" }) forces a full sweep. Fix a wrong match with
PATCH …/ads/links/{linkId} and body { "productId": "…" }.
Legacy pixel-connect routes
The pre-integration flow used for pixel discovery still exists and is public (raw access token passed by the client — prefer the store-scoped integration above for anything new):
| Method | Path | Description | Auth |
|---|---|---|---|
GET | /v1/social/facebook/marketing/redirect | Start Facebook Marketing OAuth (popup/mobile) | Public |
ANY | /v1/social/facebook/marketing/callback | Shared OAuth callback (also completes store-scoped Meta connects) | Public |
GET | /v1/social/facebook/marketing/pixels?accessToken=… | List pixels visible to the token | Public |
GET | /v1/social/facebook/marketing/mobile-result?nonce=… | One-time OAuth payload after deep-link | Public |
GET | /v1/social/meta/oauth-result?nonce=… | One-time outcome of a store-scoped Meta connect | Public |
Pixel server events
Server events need the pixel integrations, not the Meta account: configure
store.integrations.metaPixel.pixels[] (each entry: pixel id + CAPI access token key) and
store.integrations.tiktokPixel (pixel id + accessToken) via the
integrations config API. Events are built from an order and fanned
out to every configured pixel; the response reports per-pixel success.
| Method | Path | Description | Auth |
|---|---|---|---|
POST | /v1/actions/sendEventToMetaPixel | One order → all Meta pixels | Bearer |
POST | /v1/actions/sendEventsToMetaPixel | Many orders — body adds orderIds[], optional pixelIds[] subset | Bearer |
POST | /v1/actions/sendEventToTiktokPixel | One order → all TikTok pixels | Bearer |
POST | /v1/actions/sendEventsToTiktokPixel | Many orders (TikTok) | Bearer |
POST | /v1/actions/sendMetaPixelTestEvent | Test CAPI credentials — body { "id", "key", "code"? } | Bearer |
POST | /v1/actions/sendTiktokPixelTestEvent | Test Events API credentials — body { "id", "accessToken", "testCode"? } | Bearer |
POST | /v1/actions/runPixelStatusRules | Evaluate (dry-run) or fire status-transition rules for an order | Bearer |
Accepted event values:
| Platform | Events |
|---|---|
| Meta | Purchase, Lead, ViewContent, AddToCart, InitiateCheckout |
| TikTok | Purchase, PlaceAnOrder, ViewContent, AddToWishlist, Search, AddPaymentInfo, AddToCart, InitiateCheckout, CompleteRegistration |
Send a purchase event
curl -X POST "https://api.feeef.org/v1/actions/sendEventToMetaPixel" \
-H "Authorization: Bearer $FEEEF_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "event": "Purchase", "storeId": "{storeId}", "orderId": "{orderId}" }'The fan-out response (HTTP 200 even on partial failure — inspect the counters):
{
"event": "Purchase",
"orderId": "…",
"storeId": "…",
"totalPixels": 2,
"successfulPixels": 1,
"failedPixels": 1,
"successRate": 0.5,
"hasAnySuccess": true,
"results": [
{ "pixelId": "123", "pixelName": "Main", "success": true, "response": { "…": "…" } },
{ "pixelId": "456", "pixelName": "Backup", "success": false, "error": "…" }
],
"summary": { "message": "Successfully sent event to 1 out of 2 pixels" }
}Status rules
Pixel configs can carry status rules — "when the order transitions into status X, fire
event Y". They run automatically on order updates; POST /v1/actions/runPixelStatusRules
lets you audit or recover:
- Default is dry-run: reports which rules would fire for the order's transition without calling any pixel API.
"dryRun": falseactually sends."force": truefires rules whose target equals the order's current status (recovery / verification after missed sends).
The response lists outcomes per rule with wouldFire, sent, and skipReason.
Requirements checklist
- Ads reads: store has a connected Meta account (
capabilities.connectedandcanReadtrue) — tokens expire after ~60 days, watchneedsReconnect. - Meta server events:
integrations.metaPixel.pixels[]entries with valid CAPI tokens. - TikTok server events:
integrations.tiktokPixelwith a valid Events API token. - Writes to marketing configs follow the same RBAC +
store.integrationsscope rules as every integration.
Related
- Integrations — config envelope, redaction, billing
- Connectors — Facebook Lead Ads → orders import
- API conventions — errors, pagination