Pixels
A merchant pixels record stores the per-merchant configuration for ad-network tracking pixels and server-side conversion APIs (CAPI). One row per merchant. The shape mirrors what Storlaunch's storefront snippet needs to fire client-side tracking, plus the secrets needed for Ripllo to make server-side conversion calls on the merchant's behalf.
This resource has two access modes you need to keep straight:
GET /andPATCH /— auth-required. Returns the full record including CAPI access tokens. Used by the dashboard.GET /public/:accountId— no auth. Returns IDs only, never secrets. Used by Storlaunch's storefront pages to fire client-side pixel snippets.
The explicit select list on the public route is the primary guard against shipping metaCapiAccessToken to the storefront. Any future edit to this resource must be paired-reviewed with the same rigor as a payout webhook secret.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET |
/api/v1/pixels |
Get pixel config |
PATCH |
/api/v1/pixels |
Update pixel config |
GET |
/api/v1/pixels/public/:accountId |
Public pixel config (no auth, no secrets) |
Get pixel config
GET /api/v1/pixels
Returns the merchant's full pixel record, including secrets. If the merchant hasn't configured anything yet, returns a default stub with enabled: true and every provider field null, so the dashboard can render the empty state without special-casing.
Response
{
"data": {
"id": "mxp_01HX...",
"accountId": "acc_01HX...",
"metaPixelId": "1234567890",
"metaCapiAccessToken": "EAAGm…",
"metaTestEventCode": "TEST12345",
"googleAnalyticsId": "G-AB12CD34EF",
"googleAdsConversionId": "AW-1234567890",
"googleAdsPurchaseLabel": "abcDEF1234",
"tiktokPixelId": "C4ABC123…",
"enabled": true,
"createdAt": "2026-05-01T10:42:00.000Z",
"updatedAt": "2026-05-13T10:11:00.000Z"
},
"error": null,
"meta": { "requestId": "...", "timestamp": "..." }
}
| Status | error.code |
When |
|---|---|---|
403 |
NO_ACCOUNT |
Caller's token has no accountId. |
Update pixel config
PATCH /api/v1/pixels
Upserts the merchant's record. Only fields you supply are updated; omitted fields stay as-is. To clear a field, send null.
Request body
| Field | Type | Notes |
|---|---|---|
metaPixelId |
string (≤64) | null | The Meta Pixel ID, e.g. 1234567890. Safe to embed client-side. |
metaCapiAccessToken |
string (≤500) | null | The CAPI access token, used server-side by Ripllo to send conversion events to Meta's Conversions API. Never returned by the public endpoint. |
metaTestEventCode |
string (≤64) | null | Meta's test-event code for CAPI dry runs. Set during integration testing; clear once verified. |
googleAnalyticsId |
string (≤64) | null | Measurement ID, format G-XXXXXXXX. |
googleAdsConversionId |
string (≤64) | null | Google Ads conversion ID, format AW-XXXXXXXXXX. |
googleAdsPurchaseLabel |
string (≤64) | null | Google Ads conversion label for purchases. |
tiktokPixelId |
string (≤64) | null | TikTok Pixel ID. |
enabled |
boolean | Master switch — when false, the public endpoint returns null and Ripllo's server-side CAPI dispatcher skips this merchant. |
Response
The full updated MerchantPixels object (including secrets, since this is the merchant-facing endpoint).
Examples
// Node
await ripllo.pixels.update({
metaPixelId: '1234567890',
metaCapiAccessToken: process.env.META_CAPI_TOKEN,
googleAnalyticsId: 'G-AB12CD34EF',
enabled: true,
});
# Python
ripllo.pixels.update(
meta_pixel_id='1234567890',
meta_capi_access_token=os.environ['META_CAPI_TOKEN'],
google_analytics_id='G-AB12CD34EF',
enabled=True,
)
// Go
_, err := client.Pixels.Update(ctx, &ripllo.PixelsUpdateParams{
MetaPixelID: ripllo.String("1234567890"),
MetaCapiAccessToken: ripllo.String(os.Getenv("META_CAPI_TOKEN")),
GoogleAnalyticsID: ripllo.String("G-AB12CD34EF"),
Enabled: ripllo.Bool(true),
})
# curl
ripllo_curl PATCH '/api/v1/pixels' \
'{"metaPixelId":"1234567890","enabled":true}'
Public pixel config
GET /api/v1/pixels/public/:accountId
No auth. Returns a sanitized view of the merchant's pixel IDs, suitable for shipping to a storefront page. Returns null (not 404) when:
- The merchant has no config row.
- The merchant has set
enabled: false. - The merchant has a row but every IDs field is empty (i.e., nothing to fire).
This null-pass-through is what lets storefronts unconditionally request the snippet and skip rendering when it comes back falsy.
Response — success
{
"data": {
"metaPixelId": "1234567890",
"googleAnalyticsId": "G-AB12CD34EF",
"googleAdsConversionId": "AW-1234567890",
"googleAdsPurchaseLabel": "abcDEF1234",
"tiktokPixelId": "C4ABC123…",
"enabled": true
},
"error": null,
"meta": { "requestId": "...", "timestamp": "..." }
}
Response — nothing to fire
{ "data": null, "error": null, "meta": { ... } }
Note what's missing from the success response: metaCapiAccessToken and metaTestEventCode. These are server-side secrets and are never returned from /public/:accountId regardless of enabled state. If you see them leaking in any future release, file a security ticket immediately.
The merchant pixels object
| Field | Type | Nullable | Notes |
|---|---|---|---|
id |
string | no | mxp_ + ULID. |
accountId |
string | no | Unique — one row per merchant. |
metaPixelId |
string | yes | Public, embed-safe. |
metaCapiAccessToken |
string | yes | Secret. Server-side only. |
metaTestEventCode |
string | yes | Optional; only set during CAPI integration testing. |
googleAnalyticsId |
string | yes | Public. |
googleAdsConversionId |
string | yes | Public. |
googleAdsPurchaseLabel |
string | yes | Public. |
tiktokPixelId |
string | yes | Public. |
enabled |
boolean | no | Master switch. |
createdAt, updatedAt |
ISO 8601 | no |
CAPI helper: hashEmail
The Node and Python SDKs export a hashEmail(email) helper that returns the SHA-256 hex digest of email.trim().toLowerCase() — the exact normalised form Meta's CAPI expects in its em field. Use it when constructing event payloads in your own code:
import { hashEmail } from '@forjio/ripllo-node';
const em = hashEmail('Alice@Example.com');
// → "5a13d2..." (hex)
Re-implementing this normalisation incorrectly is the most common reason CAPI events don't match. The helper is exported so you never have to.
Security review checklist
When changing this resource (route, schema, or the SDK surface), confirm:
- The
/public/:accountIdselectlist explicitly lists only the public IDs — never spreads...row. metaCapiAccessTokenandmetaTestEventCodeare not on the public select list.- Any new secret field added here is added to both the merchant-facing
select(so it surfaces) and the public-facing select-exclusion list (so it doesn't leak). - The integration test in
pixels.test.tsasserts thatmetaCapiAccessTokenisundefinedin the public response.
This resource is high-blast-radius: a leak of metaCapiAccessToken lets anyone with the storefront URL impersonate the merchant when posting conversions to Meta, which corrupts attribution and can get the merchant's Meta account flagged.
Events
The pixels resource doesn't emit outbox events. Pixel configuration changes are audited via the audit log under the operating user, but they don't fan out as webhooks — treating credential changes as broadcastable events would be its own leak.