Mercury Pulsar — Operator API

Bring traffic, attribute conversions, stream retention events, and read your own analytics. Four seams plus a read API. You own the wallet, players, and PII; Mercury owns acquisition, retention, and cross-brand analytics.

Overview

Integrating takes three things: get API credentials, accept Mercury's tracked traffic at your signup URL, and send two signed webhooks back (a conversion, and lifecycle events). Then read your numbers via the Bearer read API.

SeamDirectionEndpoint
1 · AcquireMercury → youGET /go
2 · Attributeyou → MercuryPOST /track/postback
3 · Retainyou → MercuryPOST /engage/events
4 · Readyou → MercuryGET /operators/v1/*

Base URL: the host Mercury gives you (e.g. https://app.mercurypulsar.com). All examples below use that placeholder.

Authentication

You get two secrets at issuance: an API key (keyId.secret) and an HMAC secret. They are shown once.

Write seams — HMAC signature

/track/postback and /engage/events are signed. Send your key id and the HMAC-SHA256 (hex) of the raw body:

HeaderValue
x-mercury-keyYour public key id (the part before the dot in the API key).
x-signatureHMAC_SHA256_hex(rawBody, hmacSecret)
Compute the signature (shell)
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$HMAC_SECRET" | sed 's/^.* //')

Read API — Bearer token

The /operators/v1/* reads use the full API key as a Bearer token:

Authorization: Bearer mk_test_xxxx.secretsecret

Sandbox vs live

Keys are prefixed by mode:

The key's mode is the dataset. A sandbox key can never see live data and vice-versa — so you can integrate and fire test events with zero risk to production numbers. Sandbox events never message real players.

Get your keys

Generate a sandbox key yourself in the Quickstart (it also has a "Send test event" button to watch the loop work end-to-end). Live keys are issued by Mercury once you're ready to go to production.

Seam 1 · Acquire GET /go

Mercury's capture network sends a tracked click to /go, which 302-redirects the visitor to your brand's signup URL carrying a click_id. Persist that click_id on the player at registration so you can attribute the conversion later. This link is public — the link itself is the credential.

GET /go?r=ROUTE_KEY&aff=PARTNER_CODE&code=PROMO
ParamNotes
rRoute key (required).
affAffiliate/partner code (optional).
codePromo/influencer code (optional).

Seam 2 · Attribute POST /track/postback

On signup and first deposit, POST a signed conversion. Idempotent by externalId — retrying the same id is a safe no-op. Attribute by clickId (the link path) and/or promoCode (the influencer-code path).

POST /track/postback · HMAC
FieldTypeNotes
externalId *stringYour unique id for this conversion (idempotency key).
clickIdstringThe click_id Mercury passed to your signup URL.
promoCodestringPromo/influencer code used at signup (alternative attribution). couponCode is accepted as an alias.
typeenumsignup · ftd · deposit · lead (default lead).
valuenumberConversion value (clamped to ≥ 0).
currencystringDefault USD.
playerIdstringYour player id — creates/updates a shadow player for attribution.
contactstringEmail/handle for retention messaging (optional).
curl
BODY='{"externalId":"order_1","clickId":"CLICK_ID","playerId":"p1","type":"ftd","value":49.99}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$HMAC_SECRET" | sed 's/^.* //')
curl -sX POST https://app.mercurypulsar.com/track/postback \
  -H "content-type: application/json" \
  -H "x-mercury-key: mk_test_xxxx" \
  -H "x-signature: $SIG" \
  -d "$BODY"
200 OK
{ "ok": true, "id": 123, "duplicate": false }

Seam 3 · Retain POST /engage/events

Stream player lifecycle events into the CDP to power retention journeys. Accepts a single event or an array (batch). Same HMAC headers as the postback.

POST /engage/events · HMAC
FieldTypeNotes
brandSiteId *numberYour Mercury tenant (site) id.
contactId *stringYour own player/lead id.
type *enumsignup, login, session, identify, verify, pageview, lead, subscribe, unsubscribe, purchase, refund, cancel, bet, spin, win, redeem, deposit
amountnumberFor purchase/refund/redeem/deposit.
email, currency, at, attributes, metaOptional. attributes carries vertical-specific data.
curl
BODY='{"brandSiteId":12,"contactId":"p1","type":"deposit","amount":49.99,"currency":"USD"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$HMAC_SECRET" | sed 's/^.* //')
curl -sX POST https://app.mercurypulsar.com/engage/events \
  -H "content-type: application/json" -H "x-mercury-key: mk_test_xxxx" -H "x-signature: $SIG" -d "$BODY"
200 OK
{ "ok": true, "processed": 1, "errors": [] }

Read · GET /operators/v1/me

Verify a key and read its account + mode. The "does my key work?" call.

curl https://app.mercurypulsar.com/operators/v1/me \
  -H "authorization: Bearer mk_test_xxxx.secret"
→ { "ok": true, "accountId": 7, "mode": "sandbox" }

Read · GET /operators/v1/report

KPI summary scoped to your account, in your key's dataset.

{ "ok": true, "mode": "sandbox",
  "totals": { "clicks": 0, "conversions": 1, "value": 49.99, "conversionRatePct": 0 },
  "byType": [ { "type": "ftd", "count": 1, "value": 49.99 } ] }

Read · GET /operators/v1/conversions

Your conversions, newest first. Query: limit (1–100, default 25), type (signup|ftd|deposit|lead).

curl "https://app.mercurypulsar.com/operators/v1/conversions?limit=50&type=ftd" \
  -H "authorization: Bearer mk_test_xxxx.secret"

Read · GET /operators/v1/clicks

Your clicks, newest first. Query: limit (1–100, default 25).

Partner API GET /partners/v1/me

A separate read API for your partners (affiliates / agents / influencers): each partner gets its own Bearer key (issued by Mercury) and reads its own links, earnings, and payout statements — the programmatic twin of the human /partner/<code> dashboard. Same Authorization: Bearer keyId.secret scheme; the server resolves operator vs partner from the key id.

curl https://app.mercurypulsar.com/partners/v1/me \
  -H "authorization: Bearer mk_test_xxxx.secret"
→ { "ok": true, "code": "sky-aff", "name": "Sky", "kind": "affiliate", "mode": "sandbox", "trackedLinkParam": "aff=sky-aff" }

Partner API GET /partners/v1/summary

The partner's own earnings: commission owed (affiliate/agent) or payout-by-model (influencer). summary is null until something accrues.

Partner API GET /partners/v1/statements

The partner's frozen payout statements (period · owed · status · paid), newest first.

Node / Python
import { MercuryPartnerClient } from './mercury'
const partner = new MercuryPartnerClient({ baseUrl: 'https://app.mercurypulsar.com', apiKey: 'mk_test_xxxx.secret' })
await partner.me(); await partner.summary(); await partner.statements()

# Python
from mercury import MercuryPartnerClient
partner = MercuryPartnerClient(base_url="https://app.mercurypulsar.com", api_key="mk_test_xxxx.secret")
partner.me(); partner.summary(); partner.statements()

Idempotency

/track/postback is idempotent by externalId. If the same id is sent twice, the second call is a no-op and the response carries "duplicate": true. Use your own stable conversion id (order id, transaction id) as the externalId and retry safely.

Errors

Errors return a JSON body { "error": "..." } with the HTTP status:

StatusMeaningAction
400Bad request (missing externalId + attribution, invalid JSON).Fix the request.
401Invalid signature / missing or bad Bearer key.Check your key + HMAC.
404Unattributable conversion (unknown click / no resolvable code).Send a valid clickId or promoCode.
429Rate limited.Back off and retry.

SDKs

Thin, dependency-free reference clients sign requests and call every endpoint for you.

Node / TypeScript
import { MercuryClient } from './mercury'
const mercury = new MercuryClient({
  baseUrl: 'https://app.mercurypulsar.com',
  apiKey: 'mk_test_xxxx.secret',
  hmacSecret: 'your-hmac-secret',
})
await mercury.postback({ externalId: 'order_1', clickId, type: 'ftd', value: 49.99, playerId: 'p1' })
const report = await mercury.report()
Python
from mercury import MercuryClient
mercury = MercuryClient(base_url="https://app.mercurypulsar.com",
                        api_key="mk_test_xxxx.secret", hmac_secret="your-hmac-secret")
mercury.postback(external_id="order_1", click_id=click_id, type="ftd", value=49.99, player_id="p1")
report = mercury.report()

Source: sdk/node/mercury.ts and sdk/python/mercury.py. Both ship a signBody/sign_body helper matching the server's HMAC exactly.