Skip to main content
Send a purchase to Meta through Plainrouter using the @plainrouter/sdk package from server-side Node.js code. Plainrouter validates the event, normalizes and hashes supported identity fields, and sends eligible events to the Meta dataset connected to your workspace.

Before you begin

You need:

Install the Node.js SDK

Install @plainrouter/sdk:
The package is an ES module. Use import from a .mjs file or from a project whose package.json contains "type": "module".

Send a purchase

Store PLAINROUTER_SIGNAL_SECRET in your server environment. The SDK option signalTrackerSecret is its compatibility name; it expects a Signals workspace secret. Keep the configured client out of browser bundles. Pass the recorded three-field consent object from your order or CMP records. The function refuses partial or denied advertising consent; it does not obtain consent. Supply the actual purchase time and consent-capture time from your order records. Reuse a stable, non-personal order ID for retries, and send money as a decimal string such as "49.90".
Only include identity and browser identifiers you have permission to use. Omit fbp or fbc when unavailable; see browser identifier formats.

Validate a TypeScript payload

The SDK exports a runtime schema when data crosses an untrusted boundary:
Passing this schema check does not establish consent or final API acceptance. Plainrouter still validates the submitted event.

Retry without creating another event

Keep the same event_id when a timeout or queue retry repeats the same logical purchase:
  • A new event returns HTTP 202 with duplicate: false.
  • A previously accepted event_id returns HTTP 200 with duplicate: true.
  • Changing the ID on each retry defeats idempotency and can create duplicate conversions.
The SDK sends a server event; it does not trigger the managed browser Pixel. A separate browser signalq("track", ...) call generates its own ID and cannot accept the purchase:${order.id} ID used here. Choose the backend or the managed browser purchase recipe as the purchase owner. Do not also send a purchase from Stripe verified revenue for the same checkout. For a durable backend integration:
  1. Confirm settlement on your server and read the recorded consent decision. A browser success-page visit is insufficient.
  2. Persist one event payload per paid order, including event_id, the original purchase time, decimal amount, and the applicable consent snapshot. Use a unique record in your database to prevent concurrent jobs creating separate purchases.
  3. Send that stored payload from your job. On an uncertain timeout, retry the same ID and payload; do not rebuild it with the current time or fresh identity data. Check that advertising use is still permitted before a later retry.
  4. Mark ingestion complete after 202 or a duplicate 200; inspect destination delivery separately. A duplicate receipt does not update or enrich the first accepted event.
These database and job steps belong to your application. SDK request idempotency does not make a payment operation idempotent. See Meta event-ID deduplication for the distinction between API retries and browser/server pairing.

Confirm delivery

The 202 response means Plainrouter accepted the event for processing. It does not mean Meta has accepted the destination delivery yet. Use Signal health and performance or retrieve the event with getEvent to inspect its delivery state. During setup, you can also use Meta Test Events mode through the destination operations in the Conversion API reference.
Pass the event_id returned by sendPurchase. An accepted delivery confirms Meta acceptance; queued, sent, or retrying remains pending. An empty list is not acceptance. For failed:* or skipped:*, inspect the delivery explanation before replaying anything. Handle 401 by checking credentials, 404 by checking ID, scope, and retention, and 422 by correcting the request fields.

Implementation references