Authentication

Authentication

Server SDKs sign POST requests with an app key and HMAC secret. Static sites use a web token and do not sign. Click URLs do not need a credential.

POSThttps://serve.meridianads.tech/v1/decision

Static sites

HMAC stays on the server. A static page loads https://meridianads.tech/tag/v1.js with data-token="mw_live_…" and marks slots with data-meridian-placement. The tag sends X-Web-Key. It does not send X-App-Key, X-Timestamp, or X-Signature. The browser Origin must match an origin stored for that token, including scheme, host, and port. user_key is still required in the JSON body. The tag supplies it. See the JavaScript guide.

Headers

HeaderValue
X-App-Key Your app key prefix from the console, for example mk_live_…
X-TimestampUnix seconds. Default allowed skew is 300 seconds.
X-SignatureHex digest of HMAC-SHA256 over the canonical string.

Canonical string

Build a string from four parts joined by dots: {unix_timestamp}.{METHOD}.{path}.{raw_body}. Use the HTTP method as sent ( POST), the path without query string ( /v1/decision or /v1/decisions), and the exact request body bytes. Whitespace in JSON must match what you sign.

The secret shown at key creation is hex-encoded. Decode it to bytes before computing HMAC-SHA256.

Node

Node
import { createHmac } from 'node:crypto'

const ts = String(Math.floor(Date.now() / 1000))
const method = 'POST'
const path = '/v1/decision'
const body = JSON.stringify({
  placement: 'home',
  user_key: 'user-42',
  context: { country: 'US' }
})
const canonical = `${ts}.${method}.${path}.${body}`
const secret = Buffer.from(secretHex, 'hex')
const signature = createHmac('sha256', secret).update(canonical).digest('hex')

await fetch('https://serve.meridianads.tech/v1/decision', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-App-Key': prefix,
    'X-Timestamp': ts,
    'X-Signature': signature
  },
  body
})

Python

Python
import hashlib, hmac, json, time, urllib.request

ts = str(int(time.time()))
method = "POST"
path = "/v1/decision"
body = json.dumps(
    {"placement": "home", "user_key": "user-42", "context": {"country": "US"}},
    separators=(",", ":"),
)
canonical = f"{ts}.{method}.{path}.{body}"
secret = bytes.fromhex(secret_hex)
signature = hmac.new(secret, canonical.encode(), hashlib.sha256).hexdigest()
req = urllib.request.Request(
    "https://serve.meridianads.tech/v1/decision",
    data=body.encode(),
    method=method,
    headers={
        "Content-Type": "application/json",
        "X-App-Key": prefix,
        "X-Timestamp": ts,
        "X-Signature": signature,
    },
)