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.
| Seam | Direction | Endpoint |
|---|---|---|
| 1 · Acquire | Mercury → you | GET /go |
| 2 · Attribute | you → Mercury | POST /track/postback |
| 3 · Retain | you → Mercury | POST /engage/events |
| 4 · Read | you → Mercury | GET /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:
| Header | Value |
|---|---|
x-mercury-key | Your public key id (the part before the dot in the API key). |
x-signature | HMAC_SHA256_hex(rawBody, hmacSecret) |
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:
mk_test_…— sandbox. Writes test rows that are isolated from real reporting; reads return only test data.mk_live_…— live. Real data only.
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.
/go?r=ROUTE_KEY&aff=PARTNER_CODE&code=PROMO| Param | Notes |
|---|---|
r | Route key (required). |
aff | Affiliate/partner code (optional). |
code | Promo/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).
/track/postback · HMAC| Field | Type | Notes |
|---|---|---|
externalId * | string | Your unique id for this conversion (idempotency key). |
clickId | string | The click_id Mercury passed to your signup URL. |
promoCode | string | Promo/influencer code used at signup (alternative attribution). couponCode is accepted as an alias. |
type | enum | signup · ftd · deposit · lead (default lead). |
value | number | Conversion value (clamped to ≥ 0). |
currency | string | Default USD. |
playerId | string | Your player id — creates/updates a shadow player for attribution. |
contact | string | Email/handle for retention messaging (optional). |
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"
{ "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.
/engage/events · HMAC| Field | Type | Notes |
|---|---|---|
brandSiteId * | number | Your Mercury tenant (site) id. |
contactId * | string | Your own player/lead id. |
type * | enum | signup, login, session, identify, verify, pageview, lead, subscribe, unsubscribe, purchase, refund, cancel, bet, spin, win, redeem, deposit |
amount | number | For purchase/refund/redeem/deposit. |
email, currency, at, attributes, meta | — | Optional. attributes carries vertical-specific data. |
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"
{ "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.
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:
| Status | Meaning | Action |
|---|---|---|
| 400 | Bad request (missing externalId + attribution, invalid JSON). | Fix the request. |
| 401 | Invalid signature / missing or bad Bearer key. | Check your key + HMAC. |
| 404 | Unattributable conversion (unknown click / no resolvable code). | Send a valid clickId or promoCode. |
| 429 | Rate limited. | Back off and retry. |
SDKs
Thin, dependency-free reference clients sign requests and call every endpoint for you.
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()
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.