# Influence360 conversion tracking — full documentation > How conversion tracking works, and everything your account needs to run it. This file is the complete Documentation tab of https://influence360.io/integrations as a single markdown document, generated from the same copy and code examples the page renders. Everything here is public and needs no account. ## Contents 1. Endpoints and placeholders 2. How tracking works 3. Set up the pixel 4. Set up the postback 5. Set up web3 tracking 6. Event reference 7. Tokens & security ## 1. Endpoints and placeholders Every endpoint below is per-environment, not per-company — these are the real URLs. | Purpose | Endpoint | | --- | --- | | Browser pixel conversion | `POST https://tracking.influence360.io/public/pixel/conversion` | | Server postback conversion | `POST https://tracking.influence360.io/public/postback/conversion` | | Wallet binding (identify) | `POST https://tracking.influence360.io/public/pixel/identify` | | Pixel script | `https://tracking-pixel.influence360.io/v1/influence360.js` | Angle-bracket values in the examples are placeholders you replace with your own runtime values: | Placeholder | What to substitute | | --- | --- | | `` | A public token from the Tokens tab. A browser key, not a secret — it ships in your page source and is re-viewable any time. | | `` | A private token secret, shown once when you create or rotate it. Server-side only. | | `` | The ref id the visitor arrived with, read from the `influence360RefId` query parameter or the `_influence360_ref_id` first-party cookie. | | `` | The wallet address the visitor connected, from your dApp's wallet provider. | | `` | Your own stable id for the conversion, used as `dedupKey`. | ## 2. How tracking works Source: https://influence360.io/integrations ### In plain terms A creator shares a link to your site. Someone clicks it, and later does something you care about — signs up, buys something, makes a deposit. Your site tells us it happened, we work out which creator sent that person, and the creator gets paid for it. The rest of this page is how each of those steps works. ### How conversion tracking works The full path from a creator's link to a credited conversion — what runs on your site and what Influence360 does. #### Attribution — creator to landing page 1. **Creator shares link** _(Creator)_ — A unique go.influence360.io tracking link per creator. 2. **Click redirect** _(Influence360)_ — We record the click and send the visitor on to your site, tagged with a ref id — the code that says which creator sent them. 3. **Landing page** _(Browser)_ — Our snippet on your page saves that ref id in a cookie on your own domain. #### Conversion capture — your site reports the event 4. **Visitor converts** _(Your site)_ — Sign-up, purchase or other action on your site. 5. **Browser pixel** _(Your site)_ — A snippet on the page reports it from the visitor's browser. 6. **Server postback** _(Your backend)_ — Your own server reports it to us directly. #### Validation & payout — Influence360 takes over 7. **Influence360 attributes** _(Influence360)_ — We match the ref id to the creator, then run our timing, duplicate and fraud checks. 8. **Creator credited** _(Influence360)_ — Validated conversions feed dashboards and payouts. ### Attribution Every creator in a cost-per-action (CPA) campaign shares a unique tracking link. When a visitor clicks it, Influence360 records the click and forwards them to your destination URL. It adds a ref id to the web address — a short code identifying which creator sent that visitor. The pixel then stores the ref id in a cookie set on your own domain, so it is still there when the visitor converts. When the visitor converts, you report the conversion together with the ref id — from the browser via the pixel, or from your server via the postback. Influence360 matches the ref id back to the creator, then runs its checks before crediting the conversion. It has to fall inside the attribution window — the time limit after a click for a conversion to still count. It also has to be new rather than a repeat of one already reported, and it has to clear our fraud checks. ### Pixel or postback: which should you use? Two ways to tell us a conversion happened: the pixel is a snippet of code in your web page, the postback is a request your own server sends us. Both report the same events into the same attribution pipeline. What differs is what we can guarantee about the report itself — which is why anything carrying an amount belongs on your server. **Money events belong on your server** — Report Purchase and Deposit through the server postback. Sign-up, KYC verification, App install and Subscription carry no amount, so either route is fine — pick whichever is easier to reach in your stack. | What differs | Browser pixel | Server postback (recommended for money events) | | --- | --- | --- | | Best for | Events with no amount — sign-ups, installs, verifications. | Anything that decides money — purchases, deposits, refunds. | | Authentication | A public token that ships in your page source, plus the list of domains allowed to use it. Nothing secret is involved. | A secret token sent in the request header, optionally hardened with request signing (HMAC) and a list of allowed IP addresses. | | Can the amount be altered? | Yes. The amount is whatever the browser sends, so a visitor can edit it before it reaches us. | No, once request signing is on — the signature covers the whole body, amount included. | | Duplicate protection | Optional. dedupKey is your own id for the conversion; leave it out and there is no protection at all — a double-submitted checkout becomes two conversions. | Built in. dedupKey is required, so retries and replays collapse into one conversion. | | Refunds and chargebacks | Not supported. A refunded order cannot be reversed from the browser. | Send the same conversion with reversal set to true and the credit is taken back. | | Delivery | Send and hope. Ad blockers, a tab closed too early or a failed request lose events silently, with no retry. | Your server owns delivery and can retry safely: dedupKey means a repeated send counts once, never twice. | | Do you find out about failures? | No. The endpoint always returns the same empty success response (HTTP 204) by design, so a dropped event looks exactly like an accepted one. | Yes. It returns HTTP 202 when the event is accepted, and an explicit error when it is not. | | Setup effort | Around 5 minutes — one snippet, pasted site-wide. | Around 15 minutes — store the ref id on landing, then POST from your backend. | Both routes run through the same validation, duplicate checks, fraud checks and minimum-value rules — a browser-reported amount is not discounted or scored more harshly. That is precisely why an amount you cannot vouch for should never be reported from the browser in the first place. ### Attribution strictness for wallets Web3 conversions are detected on the blockchain, from the visitor's crypto wallet. For a creator to be credited, that wallet has to be linked to the referral the visitor arrived with — a wallet binding. By default any binding counts. If you want a stronger guarantee, attribution strictness lets you prefer, or require, bindings the visitor has signed with their own wallet to prove they own it. Strictness is a per-company setting — you change it on the Configuration tab under On-chain attribution. ### Test mode Events sent with the test flag are practice runs: they go through exactly the same checks as a real conversion, but are never billed and never credit a creator. Your account has a dedicated test ref id, and the Configuration tab can fire a test event for you and confirm automatically when it lands. The test ref id only works together with the test flag — real conversions must carry the ref id captured from the visitor's click. ## 3. Set up the pixel Source: https://influence360.io/integrations/pixel · ~5 min setup Report conversions straight from your website. Three steps: pick a browser key, paste one snippet site-wide, then verify with a test event. ### Step 1 — Get a public token The pixel is keyed by a public token — a browser key identifying your company. It is visible in your page source by design (not a secret) and re-viewable any time. ### Step 2 — Install the snippet Two ways to do this. **influence360.js** is the short path; **Your own code** posts the same request by hand, for teams that will not put a third-party script on their pages. Steps 1 and 3 are the same either way. #### influence360.js — Install the snippet One snippet, pasted site-wide — it loads influence360.js, captures the ref id from the creator's link and reports conversions. - Paste the snippet below on every page (e.g. in your site layout or ``). It loads influence360.js and runs `influence360('init', …)` to capture the ref id. - On each conversion success page, call `influence360('track', '', …)` with the matching event type — pass your `dedupKey`, plus the event's own field where it has one (`orderValue` for a purchase, `depositValue` for a deposit, `qualifyingPlan` for a subscription). - To send events through your own first-party proxy or a regional collector, change the `collectUrl` passed to `init`. ```html ``` #### Your own code — Call the endpoint directly The endpoint is public, so you can post to it yourself. Same URL, same body, same result: nothing downstream can tell the difference. You take on the two jobs influence360.js was doing for you, and both fail quietly if you get them wrong. **1. Capture the ref id yourself** Our redirect adds the ref id to your destination URL once, on the landing page. Nothing else will put it back, so read it there and store it before the visitor navigates away. ```js // Run on EVERY page. Our redirect adds ?influence360RefId=… to your destination URL exactly // once — on the landing page — so if you miss it there, the referral is gone. (function () { var ref = new URLSearchParams(window.location.search).get('influence360RefId'); if (!ref) return; // Same cookie name and 90-day lifetime the pixel uses, so you can switch to influence360.js // later without losing referrals already captured. document.cookie = '_influence360_ref_id=' + encodeURIComponent(ref) + '; Max-Age=7776000; Path=/; SameSite=Lax; Secure'; })(); // Read it back when the visitor converts. function influence360RefId() { var match = document.cookie.match(/(?:^|;\s*)_influence360_ref_id=([^;]*)/); return match ? decodeURIComponent(match[1]) : null; } ``` **2. Post the conversion** One request per conversion, to the same endpoint the pixel uses. The public token goes on the query string, not in the body. ```js function reportConversion(content, dedupKey) { var url = 'https://tracking.influence360.io/public/pixel/conversion?publicToken='; var body = JSON.stringify({ refId: influence360RefId(), // null when the visitor arrived without a referral — safe to send dedupKey: dedupKey, eventSourceUrl: window.location.href, clientEventAtMs: Date.now(), content: content, }); // The content type is load-bearing: 'text/plain;charset=UTF-8' is CORS-safelisted, so this // cross-origin POST skips the preflight. Sending application/json triggers a preflight that the // collector does not answer, and the event is lost with no error you can see. if (navigator.sendBeacon) { var blob = new Blob([body], { type: 'text/plain;charset=UTF-8' }); if (navigator.sendBeacon(url, blob)) return; } fetch(url, { method: 'POST', body: body, headers: { 'Content-Type': 'text/plain;charset=UTF-8' }, keepalive: true, // survives the page unload a conversion redirect usually causes mode: 'no-cors', // the reply is an empty 204; there is nothing to read }).catch(function () {}); } // On your conversion success page: reportConversion({ "type": "SIGN_UP" }, ''); ``` **Send it as text/plain, not application/json** This is the mistake that costs people an afternoon. Browsers let a cross-origin POST through without a preflight only for a few content types, and application/json is not one of them — the collector does not answer preflights, so the request never arrives. Nothing throws, the console stays clean, and your conversions simply never show up. Use text/plain;charset=UTF-8 and the browser sends it straight through. **Check it from a terminal first** The same request as curl, so you can confirm the token and body before touching your site. Set Origin to a domain the token allows — a request from an unlisted domain is discarded, and you still get the same empty success back. ```bash curl -X POST 'https://tracking.influence360.io/public/pixel/conversion?publicToken=' \ -H 'Content-Type: text/plain;charset=UTF-8' \ -H 'Origin: https://your-site.example' \ -d '{ "refId": "", "dedupKey": "", "content": { "type": "SIGN_UP" } }' ``` **What you give up** The pixel also handles cross-subdomain cookies, retry on page unload and the wallet binding used for web3 tracking. Posting directly gets you conversions only. Reversals and refunds are not available on this endpoint at all — from either the pixel or your own code — so anything carrying an amount still belongs on the server postback. **If the event you are reporting carries an amount (Purchase, Deposit), send it from your backend instead — this applies to both options above.** The amount you pass here is whatever the browser reports, and a visitor can edit it. The pixel also cannot reverse the conversion when the order is refunded, and without dedupKey a double submit counts twice. Report Purchase and Deposit through the server postback instead. ### Step 3 — Verify with a test event Fire a verification canary (never billed) from the Configuration tab — we confirm your integration automatically once it lands. ### Transparency & verification influence360.js is the script that reports conversions from your site. This page covers what it does, what it stores, what it never does, and how to verify it. #### What it stores in the browser Three writes, all first-party on your own domain. This list is complete — if you find a fourth in your browser's Application tab, that is a bug and we want the report. | Name | integrations.docs.transparency.storage.cols.kind | Lifetime | Scope | Purpose | | --- | --- | --- | --- | --- | | `_influence360_ref_id` | Cookie | 90 days | Your domain, all paths | The referral id the visitor arrived with, so a conversion can be credited to the creator who sent them. | | `_influence360_ref_id` | localStorage | until cleared | Your origin | A copy of the same referral id, so attribution survives the cookie being evicted. Not a second identifier — same key, same value. | | `__influence360_d` | Cookie | transient | Candidate parent domain | Written and deleted within the same call, to find the widest domain that accepts a cookie so a click on one subdomain converts on another. Never persists. | The referral cookie is written with Path=/; SameSite=Lax; Secure — first-party, sent only over HTTPS, and not sent on cross-site requests. Nothing is written to a domain other than yours, and nothing is read that the script did not write. If you set the cookieDomain option, the cookie is scoped to exactly that domain instead of the auto-detected one. #### What it does not do Each of these is a property of the bundle you can confirm yourself: search the source for the API it would have to call, and it is not there. - **No device fingerprinting** — No canvas, font, WebGL or audio probing, no screen or hardware enumeration, no attempt to identify a device across sites. - **Reads only what it wrote** — It reads its own referral cookie and its own localStorage key. It does not enumerate your cookies, storage or session data. - **No page content** — No form fields, no keystrokes, no clipboard, no DOM scraping, no session recording, no screenshots. - **No third-party calls** — The only request it makes is the conversion beacon to the collector shown above. No ad networks, no analytics vendors, no tag loaders, no dynamically injected scripts. - **No cross-site tracking** — Storage is first-party on your domain only. There is no third-party cookie, no iframe, no cross-site identifier, and no advertising id. - **No personal data we choose** — The only field that could carry personal data is the dedupKey your own code supplies. Send a hash or an order id — the pixel neither reads nor infers an email, a name or an address on its own. #### What happens when it fails The honest answer to “will this break my checkout?”, with the mechanism behind each guarantee named so you can check it rather than take it. - **It never throws into your page** — Every entry point is wrapped, including storage access and the network call. A failure inside the tracker cannot become an exception in your own code. - **It never blocks rendering** — The snippet loads the script asynchronously, and conversions are sent fire-and-forget through sendBeacon (or a keepalive fetch). Nothing waits on a response, and there is no response to wait for. - **Blocked storage is not an error** — In private mode, with storage disabled, or under a sandbox, reads and writes fail silently. Attribution is lost for that visitor; the page is unaffected. - **A tampered build fails closed** — If you pin a version with an integrity hash, a browser that receives different bytes refuses to execute them. The worst case is no tracking, never wrong tracking or unexpected code. #### Verify the bytes you load Pinned builds are immutable and never republished with different bytes, so a hash that matched yesterday still matches today. The manifest is the authoritative record of what we have published. Manifest: https://tracking-pixel.influence360.io/manifest.json - **1. Hash what the CDN served you** — Needs nothing but curl. Proves the file your visitors receive is the file listed in the manifest — the same sha384 a pinned snippet carries. - **2. Check the build provenance** — Every published build carries a sigstore attestation binding its digest to the workflow, repository and commit that produced it. Proves the bytes came out of our public build pipeline and not from someone with CDN access. - **3. Rebuild it yourself** — The build is reproducible: rebuilding the commit shown in the Commit column above produces byte-identical output. The command prints a sha256 — compare it with the one in the table. This is the check that requires trusting nobody: not us, and not GitHub. **What the provenance attestation proves** — Builds from this repository are signed by public sigstore and recorded in its public Rekor transparency log, so the attestation is independently auditable: you can confirm the bytes came out of this repository's workflow without taking our word for it, or GitHub's. Verified on the current build — the signing certificate is issued by sigstore.dev, and the Rekor entry is retrievable anonymously with a signed inclusion proof. Builds published before this repository became public on 5 August 2026 were signed by GitHub's own sigstore instance instead and carry no public log entry. Step 3 goes further still, tying those bytes to source you can read. #### Staying informed, and reporting a problem A pinned version never changes under you. If you use the auto-update channel, or your script-monitoring tool alerts on a change, these are how you correlate and how you reach us. | Resource | URL | | --- | --- | | Published-builds feed (Atom) | https://influence360.io/pixel-builds.xml | | Report a vulnerability | https://github.com/Influence360/tracking-pixel/security/advisories/new | | View the source | https://github.com/Influence360/tracking-pixel | | Apache-2.0 licence | https://github.com/Influence360/tracking-pixel/blob/main/LICENSE | ## 4. Set up the postback Source: https://influence360.io/integrations/postback · ~15 min setup · Recommended for money events Report conversions from your backend — authenticated, idempotent and reversible. Works with or without the browser pixel. **Use this for anything that decides money** — Purchase and Deposit amounts set what a creator gets paid. Reported from your backend, the request is authenticated, the amount can be signed so nobody can alter it, dedupKey makes retries safe, and a refund can be reversed. None of that is possible from the browser pixel. ### Step 1 — Create an API token Postbacks authenticate with a private API token. The secret is shown once, when you create or rotate the token — store it on your server and never expose it in the browser. ### Step 2 — Capture the ref id When a visitor arrives through a creator's link, our redirect appends `?influence360RefId=…` to your destination URL. Store that value against the visitor (session, your own cookie or the user record) — you will send it back as `refId` with each conversion. Also running the browser pixel? It already persists the same value in the `_influence360_ref_id` first-party cookie, so your server can read it from there instead. ### Step 3 — Send the postback POST a JSON body with the ref id and the conversion details — the campaign is resolved from the ref id. - When the user converts, POST a JSON body with the ref id and a `content` object holding the conversion (its `type` plus that type's own fields). The campaign is resolved from the ref id. - Authenticate the request with the `Authorization: Bearer ` header. ```bash curl -X POST 'https://tracking.influence360.io/public/postback/conversion' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "refId": "", "dedupKey": "", "content": { "type": "SIGN_UP" } }' ``` | Field | Description | | --- | --- | | `Authorization` | Authenticates your server. The secret is shown only once when you create or rotate a token — paste your stored secret in place of . Lost it? Rotate the token on the Tokens page. | | `refId` | Identifies the creator's link the visitor came from. The pixel captures it automatically from the influence360RefId query parameter on your destination URL; on your server, send back the same ref id (read it from the _influence360_ref_id cookie / your session). To test, use the Test ref id with "test": true. | | `dedupKey` | Your own stable id for this conversion (order id, user id). We use it to ignore duplicate reports if your server retries. | ### Step 4 — Verify with a test event Fire a verification canary (never billed) from the Configuration tab — we confirm your integration automatically once it lands. ## 5. Set up web3 tracking Source: https://influence360.io/integrations/web3 · ~10 min setup On-chain conversions are detected for you — what you integrate is the link between the visitor's wallet and the creator who sent them. Four steps. **Detected does not mean automatic** — We watch your contract and see the on-chain action, but the chain does not say who referred the wallet that performed it. Tell us which wallet belongs to which referral and the creator gets credited; skip it and the conversion is detected, unattributed and never paid out. _Snippets in this section are shown for `ETHEREUM`; substitute the chain of the wallet the visitor connected._ ### Step 1 — Get a public token Wallet bindings are keyed by the same public token as the browser pixel — a browser key identifying your company, visible in your page source by design and re-viewable any time. ### Step 2 — Install the pixel to capture the ref id Paste this on every page. It stores the ref id from the creator's link in a first-party cookie — the binding in the next step reads it from there, so nothing works without it. ```html ``` ### Step 3 — Bind the wallet when it connects One call, in your wallet-connect handler. It is fire-and-forget, never throws into your page, and does nothing when no referral was captured — so it is safe to call unconditionally. - Call `influence360('identify', address, …)` as soon as a wallet connects, and again whenever the connected account changes. - Pass the `chain` of the connected wallet. It is optional metadata for a plain binding, but required if you later add signatures — it selects how the signature is verified. - Re-binding the same wallet to the same referral is harmless; repeats are deduplicated. A wallet that later arrives through a different creator's link is re-attributed to the most recent referral. ```js // Run once the visitor connects a wallet (and again on account switch). async function onWalletConnected(address) { influence360('identify', '', { chain: 'ETHEREUM' }); } ``` Bindings for TRON are accepted, but signature verification for TRON is not supported yet — they can only ever be unsigned. If your attribution strictness is set to Require signed, TRON conversions will not be credited. ### Step 4 — Verify with a test binding Add the test flag while wiring this up. A test binding runs the same validation and shows up in Test events on the Configuration tab, but is never used to credit a payout. ### Signed bindings (hardening) A signed binding carries a wallet signature proving the visitor actually controls the address, so nobody can bind a wallet they do not own. Worth adding for every integration: the default attribution strictness already prefers signed bindings over unsigned ones for the same wallet, and Require signed accepts nothing else. Unsigned bindings keep working either way — this only decides which one wins. The pixel builds the message and sends the binding, but it will not sign for you — the signature has to come from the visitor's own wallet, and how you request one differs per chain and wallet library. So you produce the signature and hand it to the same identify call. #### The message to sign The wallet must sign exactly this string — line breaks included, no trailing newline, and issuedAt equal to the signedAtMs you send. Any deviation and the binding is stored as unsigned. The timestamp must be within about 10 minutes of our server time. ```text influence360 wallet attribution ref: wallet: chain:ETHEREUM issuedAt:1700000000000 ``` #### Producing a signed binding ```js // A signed binding proves the visitor controls the wallet. Required when your attribution // strictness is "Require signed"; it also wins over an unsigned binding under "Prefer signed". async function onWalletConnected(address) { const signedAtMs = Date.now(); // 1. Ask the pixel for the exact message to sign — never hand-roll it, a single character of // difference and the signature will not verify (the binding is kept, but unsigned). const message = influence360.bindingMessage(address, 'ETHEREUM', signedAtMs); if (!message) return; // no referral captured — nothing to bind // 2. Sign it with the wallet client you already have. EVM shown; on Solana sign the same UTF-8 // bytes with ed25519 and hex-encode the 64-byte signature. const signature = await window.ethereum.request({ method: 'personal_sign', params: [message, address], }); // 3. Send the binding with the proof attached. Pass the SAME signedAtMs you signed with. influence360('identify', address, { chain: 'ETHEREUM', signature, signedAtMs }); } ``` Signature verification is supported on: ETHEREUM, POLYGON, ARBITRUM, BASE, BSC, AVALANCHE, OPTIMISM, MANTLE, SOLANA. Bindings on TRON are accepted but always unsigned. ### The binding endpoint Bind from something other than our pixel — a mobile wallet flow or your own script — by posting the same body yourself. The public token goes on the query string, not in the body. | Field | Requirement | Description | | --- | --- | --- | | `refId` | Required | The ref id the visitor arrived with, from the pixel's first-party cookie. The binding is tied to this referral. | | `wallet` | Required | The wallet address the visitor connected — the address we match against on-chain activity. | | `chain` | Optional | The chain of the connected wallet. Metadata for a plain binding; required when you send a signature, as it selects the verification scheme. | | `signature` | Optional | Hex wallet signature over the canonical binding message, proving control of the address. Absent or invalid means the binding is kept but unsigned. | | `signedAtMs` | Optional | Epoch milliseconds the signature was issued — the same value used as issuedAt in the signed message. Required whenever a signature is sent. | | `test` | Optional | Marks a canary binding — validated the same way, never used to credit a payout. | ```bash curl -X POST 'https://tracking.influence360.io/public/pixel/identify?publicToken=' \ -H 'Content-Type: application/json' \ -d '{ "refId": "", "wallet": "", "chain": "ETHEREUM" }' ``` **Binding from browser JavaScript** A backend, a script or a native mobile wallet flow can post the JSON above as-is. From browser JavaScript the content type has to change: send text/plain;charset=UTF-8, not application/json. Only a few content types are allowed through a cross-origin POST without a preflight, and the collector does not answer preflights — send JSON from a page and the binding never arrives, with nothing logged and the same empty success returned. ```js // Run once the visitor connects a wallet (and again on account switch). async function bindWallet(address) { var refId = influence360RefId(); // your own reader — see the pixel guide's "Your own code" tab if (!refId) return; // no referral captured, nothing to bind var url = 'https://tracking.influence360.io/public/pixel/identify?publicToken='; var body = JSON.stringify({ refId: refId, wallet: address, chain: 'ETHEREUM' }); // 'text/plain;charset=UTF-8' is CORS-safelisted, so this cross-origin POST skips the // preflight. application/json triggers one that is never answered — the binding is lost with no // error you can see, and the endpoint answers 204 either way. if (navigator.sendBeacon) { var blob = new Blob([body], { type: 'text/plain;charset=UTF-8' }); if (navigator.sendBeacon(url, blob)) return; } fetch(url, { method: 'POST', body: body, headers: { 'Content-Type': 'text/plain;charset=UTF-8' }, keepalive: true, mode: 'no-cors', }).catch(function () {}); } ``` Responses are always empty with no error detail, so a prober learns nothing: a binding from a domain that is not allow-listed on the token is dropped exactly like a valid one. If bindings are not landing, check the token's allowed domains and the Test events feed. ## 6. Event reference Source: https://influence360.io/integrations/events The complete catalog of conversion events, with the exact request each one needs. Web2 events are reported by you, from the browser or your backend; web3 events are detected on-chain and never sent. ### Request envelope Both transports share one shape: the common fields live in the envelope, and the event-specific fields live inside the `content` object, selected by its `type`. There is no top-level event field. | Field | Browser pixel | Server postback | Description | | --- | --- | --- | --- | | `refId` | Required | Required | The ref id captured from the creator's link — the campaign and creator are resolved from it. | | `content` | Required | Required | The event-specific object. Its type field selects the event (catalog below) and gates which other fields it carries. | | `publicToken` | Required | — | Your public token (browser key), sent as the ?publicToken= query parameter on the request URL — not in the JSON body. Identifies your company and is checked against the token's allowed domains. | | `dedupKey` | Recommended | Required | Your stable id for this conversion (order or user id). Required on the postback — it is what makes retries safe; strongly recommended on the pixel. | | `test` | Optional | Optional | Marks a verification canary — validated through the full pipeline but never billed. | | `reversal` | — | Optional | Set true to reverse a previously reported conversion (refund or chargeback). | | `clientEventAtMs` | Optional | Optional | Optional epoch-millis timestamp of when your side observed the event. Diagnostic only — we record the authoritative time on receipt, so it never affects billing or attribution; it just helps you spot delivery lag on queued or retried events. | | `eventSourceUrl` | Optional | — | The page URL the event fired on. The pixel script captures it automatically — you only set it yourself when posting to the pixel endpoint directly. Diagnostic only; never used for billing or attribution. | **Authentication differs** — The pixel carries your public token as the ?publicToken= query parameter on the request URL (not in the body); the postback authenticates with the Authorization Bearer header (plus optional request signing and IP rules). Money values inside content are strings, e.g. "49.99" — the same in the pixel's JS API and in the postback body. ### Web2 events — you report these You report these from your website (pixel) or backend (postback). Pick a transport to see the exact request for each event. The events below that carry an amount decide a payout. From the browser that amount is whatever the page reports, cannot be reversed after a refund, and is only deduplicated if you send dedupKey — report those from your backend instead. #### Sign-up (`SIGN_UP`) A new user registers on your product. No event-specific fields — content carries only its type Postback (curl): ```bash curl -X POST 'https://tracking.influence360.io/public/postback/conversion' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "refId": "", "dedupKey": "", "content": { "type": "SIGN_UP" } }' ``` Pixel (JS) — Assumes the pixel snippet is installed — see the pixel set-up guide. ```js influence360('track', 'SIGN_UP', { dedupKey: '' }); ``` Your own code (JS) — No SDK: assumes you capture the ref id yourself and read it back with influence360RefId() — see "Your own code" in the pixel set-up guide. ```js navigator.sendBeacon( 'https://tracking.influence360.io/public/pixel/conversion?publicToken=', // text/plain is required from a browser — application/json is dropped at the preflight. new Blob([JSON.stringify({ refId: influence360RefId(), dedupKey: '', content: { "type": "SIGN_UP" }, })], { type: 'text/plain;charset=UTF-8' }), ); ``` #### KYC verification (`KYC_VERIFICATION`) A user completes identity verification (KYC). No event-specific fields — content carries only its type Postback (curl): ```bash curl -X POST 'https://tracking.influence360.io/public/postback/conversion' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "refId": "", "dedupKey": "", "content": { "type": "KYC_VERIFICATION" } }' ``` Pixel (JS) — Assumes the pixel snippet is installed — see the pixel set-up guide. ```js influence360('track', 'KYC_VERIFICATION', { dedupKey: '' }); ``` Your own code (JS) — No SDK: assumes you capture the ref id yourself and read it back with influence360RefId() — see "Your own code" in the pixel set-up guide. ```js navigator.sendBeacon( 'https://tracking.influence360.io/public/pixel/conversion?publicToken=', // text/plain is required from a browser — application/json is dropped at the preflight. new Blob([JSON.stringify({ refId: influence360RefId(), dedupKey: '', content: { "type": "KYC_VERIFICATION" }, })], { type: 'text/plain;charset=UTF-8' }), ); ``` #### App install (`APP_INSTALL`) A user installs your mobile app. No event-specific fields — content carries only its type Postback (curl): ```bash curl -X POST 'https://tracking.influence360.io/public/postback/conversion' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "refId": "", "dedupKey": "", "content": { "type": "APP_INSTALL" } }' ``` Pixel (JS) — Assumes the pixel snippet is installed — see the pixel set-up guide. ```js influence360('track', 'APP_INSTALL', { dedupKey: '' }); ``` Your own code (JS) — No SDK: assumes you capture the ref id yourself and read it back with influence360RefId() — see "Your own code" in the pixel set-up guide. ```js navigator.sendBeacon( 'https://tracking.influence360.io/public/pixel/conversion?publicToken=', // text/plain is required from a browser — application/json is dropped at the preflight. new Blob([JSON.stringify({ refId: influence360RefId(), dedupKey: '', content: { "type": "APP_INSTALL" }, })], { type: 'text/plain;charset=UTF-8' }), ); ``` #### Purchase (`PURCHASE`) _Value-gated · Postback recommended_ A user makes a purchase. Send the order amount as orderValue. Event-specific fields: | Field | Requirement | Description | | --- | --- | --- | | `orderValue` | Required | The conversion amount, as a JSON string (e.g. "49.99"). Must meet the action's configured minimum, or the conversion is rejected. | Postback (curl): ```bash curl -X POST 'https://tracking.influence360.io/public/postback/conversion' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "refId": "", "dedupKey": "", "content": { "type": "PURCHASE", "orderValue": "49.99" } }' ``` Pixel (JS) — Assumes the pixel snippet is installed — see the pixel set-up guide. ```js influence360('track', 'PURCHASE', { dedupKey: '', orderValue: '49.99' }); ``` Your own code (JS) — No SDK: assumes you capture the ref id yourself and read it back with influence360RefId() — see "Your own code" in the pixel set-up guide. ```js navigator.sendBeacon( 'https://tracking.influence360.io/public/pixel/conversion?publicToken=', // text/plain is required from a browser — application/json is dropped at the preflight. new Blob([JSON.stringify({ refId: influence360RefId(), dedupKey: '', content: { "type": "PURCHASE", "orderValue": "49.99" }, })], { type: 'text/plain;charset=UTF-8' }), ); ``` #### Deposit (`DEPOSIT`) _Value-gated · Postback recommended_ A user funds their account. Send the deposit amount as depositValue. Event-specific fields: | Field | Requirement | Description | | --- | --- | --- | | `depositValue` | Required | The conversion amount, as a JSON string (e.g. "49.99"). Must meet the action's configured minimum, or the conversion is rejected. | Postback (curl): ```bash curl -X POST 'https://tracking.influence360.io/public/postback/conversion' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "refId": "", "dedupKey": "", "content": { "type": "DEPOSIT", "depositValue": "49.99" } }' ``` Pixel (JS) — Assumes the pixel snippet is installed — see the pixel set-up guide. ```js influence360('track', 'DEPOSIT', { dedupKey: '', depositValue: '49.99' }); ``` Your own code (JS) — No SDK: assumes you capture the ref id yourself and read it back with influence360RefId() — see "Your own code" in the pixel set-up guide. ```js navigator.sendBeacon( 'https://tracking.influence360.io/public/pixel/conversion?publicToken=', // text/plain is required from a browser — application/json is dropped at the preflight. new Blob([JSON.stringify({ refId: influence360RefId(), dedupKey: '', content: { "type": "DEPOSIT", "depositValue": "49.99" }, })], { type: 'text/plain;charset=UTF-8' }), ); ``` #### Subscription (`SUBSCRIPTION`) _Plan required_ A user starts a paid subscription. Send the plan they subscribed to as qualifyingPlan — the payout is decided by matching it against the action's plan tiers, so no amount is sent. Event-specific fields: | Field | Requirement | Description | | --- | --- | --- | | `qualifyingPlan` | Required | The identifier of the plan the user subscribed to (e.g. "pro-monthly"). | Postback (curl): ```bash curl -X POST 'https://tracking.influence360.io/public/postback/conversion' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "refId": "", "dedupKey": "", "content": { "type": "SUBSCRIPTION", "qualifyingPlan": "pro-monthly" } }' ``` Pixel (JS) — Assumes the pixel snippet is installed — see the pixel set-up guide. ```js influence360('track', 'SUBSCRIPTION', { dedupKey: '', qualifyingPlan: 'pro-monthly' }); ``` Your own code (JS) — No SDK: assumes you capture the ref id yourself and read it back with influence360RefId() — see "Your own code" in the pixel set-up guide. ```js navigator.sendBeacon( 'https://tracking.influence360.io/public/pixel/conversion?publicToken=', // text/plain is required from a browser — application/json is dropped at the preflight. new Blob([JSON.stringify({ refId: influence360RefId(), dedupKey: '', content: { "type": "SUBSCRIPTION", "qualifyingPlan": "pro-monthly" }, })], { type: 'text/plain;charset=UTF-8' }), ); ``` ### Web3 events — detected on-chain Detected on-chain by watching the contract configured on the action — you never send these. A postback carrying one of these types is rejected outright; a pixel carrying one is dropped during attribution. Either way it is never credited. Detected is not the same as credited: the chain does not say who referred the wallet. You have to bind the connected wallet to the referral with the pixel's identify call, or these conversions are never attributed to a creator. See section 5 (Set up web3 tracking). | Event | Description | | --- | --- | | Wallet activity (`WALLET_ACTIVITY`) | A wallet interacts with your configured contract. | | Token acquisition (`TOKEN_ACQUISITION`) | A wallet acquires at least the configured minimum amount of your token. (Value-gated) | | Deposit / stake (`DEPOSIT_STAKE`) | A wallet deposits or stakes at least the configured minimum into your contract. (Value-gated) | | NFT mint (`NFT_MINT`) | A wallet mints from your configured NFT collection. | ## 7. Tokens & security Source: https://influence360.io/integrations/security Two kinds of token authenticate your traffic, and four controls keep that traffic yours: allowed domains, request signing, IP allow-lists and rotation. ### The two token kinds | | Public token | Private token | | --- | --- | --- | | Summary | Keys the browser pixel. Meant to be visible in your page source — not a secret. Re-viewable any time; disable or rotate without touching your other tokens. | Authenticates server postbacks. The secret is shown only once when created or rotated, so store it securely and never expose it in the browser. | | Visibility | Public — visible in page source | Secret — server-side only | | Used by | Browser pixel | Server postback | | Sent as | ?publicToken= query param | Authorization: Bearer … | | Secret shown | Not a secret · re-viewable | Once, at create / rotate | ### Security controls #### Allowed domains (Public token) Each public token can include a domain allow-list. Events sent from pages on unapproved domains are silently discarded. The pixel still receives an empty success response, preventing attackers from learning which domains are allowed through probing. An empty list allows all domains. Entries include subdomains, so example.com also covers shop.example.com. #### Request signing (HMAC) (Private token) A private token can include an HMAC secret. Your server sends X-Timestamp and X-Signature (a hex HMAC-SHA256 of the timestamp, newline, and raw body). We verify both and reject mismatches, so the bearer token alone is not enough. The X-Timestamp must be within a short tolerance of server time, which bounds replays; dedupKey then keeps an accepted conversion counted once. #### IP allow-list (Private token) A private token can be restricted to a set of IP addresses or CIDR ranges. Postbacks from any other address are rejected regardless of credentials. Combine with signing for defence in depth: the allow-list stops stray callers, the signature proves the payload came from you. #### Rotation (Both tokens) Rotate a token whenever a secret may have leaked, when someone with access leaves, or on your regular security schedule. Rotation invalidates the old value immediately. Keep two tokens per surface during planned rotations: add the new one, deploy, then revoke the old — zero downtime.