Developer guide · Server events

Report the customer milestone after your server proves it happened.

The browser supplies acquisition context. Your Shopify app server supplies installation, trial, qualification and payment evidence with one stable event ID.

Event contract

  1. 01install: after Shopify HMAC and OAuth state/nonce validation
  2. 02trial_started: after your billing system records the trial
  3. 03trial_converted: when that trial becomes paid
  4. 04paid: after a verified payment or paid subscription start; include positive amountCents and currency when known
  5. 05qualified: only after your own documented server rule passes
  6. 06Reuse the same eventId for retries
  7. 07Use the same acquisitionId captured before installation
  8. 08Use the stable myshopify.com domain or internal merchant ID as customerRef

Next.js or Remix server

await fetch('https://app.withmarlo.app/api/tracking/server-events', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MARLO_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    teamSlug: 'acme',
    publicKey: process.env.MARLO_PUBLIC_KEY,
    eventId: billingEvent.id,
    acquisitionId: session.marloAcquisitionId,
    name: 'paid',
    customerRef: session.shop,
    amountCents: 4900,
    currency: 'USD',
    occurredAt: billingEvent.createdAt,
  }),
})

Authenticate the calling route and load the acquisition ID from your own signed session or database. Never accept a browser-supplied merchant identity as payment evidence.

Expected response

A first request returns {"accepted":true,"duplicate":false}. Repeating the same source event ID returns {"accepted":true,"duplicate":true}. A mapped Google Ads row is then queued, validated or recorded as unattributed.

Verification

  1. 01Open Tracking and confirm the event is marked Server
  2. 02Confirm customerRef and event time match the source record
  3. 03Open Google Ads and find the same event type
  4. 04Confirm click evidence is present or investigate the first-party handoff
  5. 05In validation-only mode expect validated rather than an applied Google conversion
  6. 06Do not change the event ID merely to bypass a duplicate

Failure handling

  1. 01400: validate required strings, ISO timestamp, supported event name and amount/currency pair
  2. 02401: verify team slug, private key and tracking source ownership
  3. 03Duplicate: treat as successful idempotent delivery
  4. 04Unattributed: inspect click capture and acquisition handoff; do not fabricate an ID
  5. 05Rejected: use the displayed Google reason before retrying
  6. 06Timestamp: send the real event time and deliver within seven days to Marlo

Security and limits

  1. 01Keep marlo_sk_ in a secret manager and rotate it from MCP if exposed
  2. 02Do not log the private key or put it in a browser bundle
  3. 03Do not weaken Shopify OAuth CSRF checks
  4. 04Do not send merchant email or unrelated customer data to create an ad match
  5. 05Marlo sends only eligible mapped events that have a supported captured click ID
  6. 06Mapping creation is not retroactive

Return to the complete Google Ads connection guide for account setup, validation, diagnostics and disconnection.