Skip to content
Signed Log Verification

Verify Any Auction, Pod, or Session

Every decision ApexMediation makes is cryptographically signed. Here's how to verify it.

Why Signed Logs Matter

When you're reconciling with partners or investigating a discrepancy, you need evidence that can't be disputed. Our signed logs provide:

Tamper Evidence

Any modification to the log invalidates the signature.

Non-Repudiation

We can't deny what our system decided—it's signed.

Independent Verification

You can verify signatures without our servers.

How to Verify

Export the Auction Receipt

Export the signed auction receipt from the Console, or fetch it via the Transparency API.

# Fetch a specific auction (requires auth)
# Tip: includeCanonical=1 returns the canonical string to verify.

curl -s   -H "Authorization: Bearer $APEX_TOKEN"   "https://api.apexmediation.ee/api/v1/transparency/auctions/auc_abc123?includeCanonical=1" | jq . > auction.json

Inspect the Bundle Structure

The receipt includes the signature, key id, algorithm, and (optionally) the canonical string.

{
  "sessionId": "sess_abc123",
  "bundleId": "bundle_abc123",
  "auction_id": "auc_abc123",
  "timestamp": "2025-12-15T10:30:00Z",
  "winner": { "source": "network_a", "bid_ecpm": 2.5, "currency": "USD" },
  "integrity": {
    "algo": "ed25519",
    "key_id": "key_2025Q4",
    "signature": "<base64 Ed25519 signature>"
  },
  "canonical": {
    "string": "<canonical JSON string placeholder>",
    "truncated": false,
    "size_bytes": 1234
  }
}

Verify the Signatures

Verify locally (offline) once you have the receipt JSON.

# Extract canonical string + signature from the receipt
jq -r '.canonical.string' auction.json > canonical.txt
jq -r '.integrity.signature' auction.json | base64 -d > signature.bin

# Confirm metadata
jq -r '.integrity.algo' auction.json    # ed25519
jq -r '.integrity.key_id' auction.json  # key_2025Q4

Manual Verification (OpenSSL)

For independent verification without our tools:

# 1. Download our public key (rotated quarterly)
curl -s https://api.apexmediation.ee/api/v1/transparency/keys | jq .

# If you want a PEM file for a specific key_id:
curl -s https://api.apexmediation.ee/api/v1/transparency/keys | \
  jq -r '.data[] | select(.key_id=="key_2025Q4") | (.public_key_pem // empty)' > apex-key.pem

# If your response doesn't include public_key_pem, fall back to public_key_base64:
curl -s https://api.apexmediation.ee/api/v1/transparency/keys | \
  jq -r '.data[] | select(.key_id=="key_2025Q4") | .public_key_base64' | \
  awk 'BEGIN{print "-----BEGIN PUBLIC KEY-----"} {print} END{print "-----END PUBLIC KEY-----"}' > apex-key.pem

# 2. Verify with OpenSSL (Ed25519 verifies the message directly; no hashing step)
openssl pkeyutl -verify -pubin -inkey apex-key.pem \
  -sigfile signature.bin -in canonical.txt

# Output: "Verified OK" if valid

What Evidence Looks Like

Here's a sample of what each component contains.

Cue Timeline

[
  { "timestamp": "2025-12-15T10:30:00.123Z", "cueId": "cue_001", "type": "start", "mediaTime": 120.5 },
  { "timestamp": "2025-12-15T10:30:30.456Z", "cueId": "cue_001", "type": "end", "mediaTime": 150.5 }
]

Pod Decision

{
  "podId": "pod_abc123",
  "slots": 2,
  "filled": 2,
  "ads": [
    { "creativeId": "cr_001", "partner": "partner_a", "duration": 15, "bid": 12.50 },
    { "creativeId": "cr_002", "partner": "partner_b", "duration": 15, "bid": 10.25 }
  ],
  "decisionLatencyMs": 45,
  "timestamp": "2025-12-15T10:30:00.200Z"
}

Tracking Events

[
  { "eventType": "impression", "adId": "ad_001", "timestamp": "2025-12-15T10:30:01.000Z" },
  { "eventType": "start", "adId": "ad_001", "timestamp": "2025-12-15T10:30:01.050Z" },
  { "eventType": "firstQuartile", "adId": "ad_001", "timestamp": "2025-12-15T10:30:04.750Z" },
  { "eventType": "midpoint", "adId": "ad_001", "timestamp": "2025-12-15T10:30:08.500Z" },
  { "eventType": "thirdQuartile", "adId": "ad_001", "timestamp": "2025-12-15T10:30:12.250Z" },
  { "eventType": "complete", "adId": "ad_001", "timestamp": "2025-12-15T10:30:16.000Z" }
]

Incident Bundle Export

When something goes wrong, here's what you (and your partners) receive:

  • Complete Trace

    Request flow from SDK to partners and back, with timestamps.

  • Decision Rationale

    Why each ad was selected or rejected (format, latency, bid, cap).

  • Partner Responses

    What each partner returned (sanitized of sensitive data).

  • Cryptographic Signatures

    All components signed for tamper-evidence.

  • Reconciliation Data

    Event counts, discrepancies, and resolution notes.

Try it yourself

Run a synthetic stream in our sandbox and export a real evidence bundle to verify.