Skip to main content
Use the server events API to report conversions that happen on your server — purchases, confirmed sign-ups, leads, or any backend action you want to attribute to a QR Code scan.

Endpoint

POST https://track.scanova.io/server-events
Required headers:
Content-Type: application/json
X-API-Key: YOUR_SITE_API_KEY

Required fields

FieldDescription
site_idYour tracking site ID from the dashboard
event_nameThe conversion event name (e.g. purchase, signup, lead)
scan_session_idThe scan session ID from the user’s browser. This links the conversion to the QR scan.

Examples

curl -X POST "https://track.scanova.io/server-events" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "site_id": "YOUR_SITE_ID",
    "event_name": "purchase",
    "event_id": "550e8400-e29b-41d4-a716-446655440000",
    "scan_session_id": "7ad26d4f-3181-4ef8-b6ca-b8f59499dd43",
    "conversion_value": { "amount": 49.99, "currency": "USD" },
    "properties": { "order_id": "ord_9876", "plan": "pro" }
  }'

Optional fields

FieldDescription
event_idUUID for safe retries. Generate once and reuse on retry. If omitted, one is auto-generated.
event_timeISO 8601 timestamp of when the event occurred. Defaults to time of receipt. Useful if you are sending events asynchronously.
conversion_value{ "amount": 49.99, "currency": "USD" }. Currency must be a 3-letter ISO 4217 code.
user_identifiersHashed user identifiers: email_hash, phone_hash, external_id. Never send raw email or phone.
propertiesCustom key-value object. Max 10 KB. No raw PII.
consentgranted, denied, or pending. Controls PII handling.

Passing scan_session_id from browser to server

The scan_session_id originates in the browser. You need to pass it from your frontend to your backend. Option 1: Hidden form field
<form action="/checkout" method="POST">
  <input type="hidden" name="scan_session_id" id="scan_session_id_field">
  <!-- other form fields -->
</form>

<script>
  // _scnv is the SDK's internal localStorage key (structure may change in future SDK versions)
  const stored = localStorage.getItem('_scnv');
  const sessionId = stored ? JSON.parse(stored).sid : null;
  if (sessionId) {
    document.getElementById('scan_session_id_field').value = sessionId;
  }
</script>
Option 2: Include in API request body from frontend
// _scnv is the SDK's internal localStorage key (structure may change in future SDK versions)
const stored = localStorage.getItem('_scnv');
const scanSessionId = stored ? JSON.parse(stored).sid : null;

await fetch('/api/checkout', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    cart: cartData,
    scan_session_id: scanSessionId,  // pass to your server
  }),
});

Sending a batch of events

Use the batch endpoint to send up to 100 events in a single request:
POST https://track.scanova.io/server-events/batch
{
  "events": [
    {
      "site_id": "YOUR_SITE_ID",
      "event_name": "purchase",
      "scan_session_id": "7ad26d4f-...",
      "conversion_value": { "amount": 49.99, "currency": "USD" }
    },
    {
      "site_id": "YOUR_SITE_ID",
      "event_name": "signup",
      "scan_session_id": "3b5e1234-..."
    }
  ]
}
The response includes a per-event accepted/rejected breakdown:
{
  "accepted": 2,
  "rejected": 0,
  "results": [
    { "index": 0, "event_id": "...", "status": "accepted" },
    { "index": 1, "event_id": "...", "status": "accepted" }
  ]
}

Next steps