HTTP API

Simple REST endpoints. No API keys for ingestion — first-party by design.

1 Ingest events

POST /api/canopy/event — accepts single or batch events. No auth, first-party only.

Request

POST /api/canopy/event
Content-Type: application/json

{
  "s": "canopy_example_com",  // site ID (required)
  "n": "pageview",            // event name (required)
  "u": "https://example.com/pricing",
  "p": "/pricing",
  "r": "https://google.com",
  "t": "Pricing - Example",
  "w": 1440,
  "props": { "utm_source": "newsletter" },
  "sid": "abc123"             // optional session ID
}

Fields

FieldRequiredDescription
syesSite ID (e.g. canopy_example_com)
nyesEvent name (pageview, checkout, etc.)
unoFull URL
pnoPath (/pricing)
rnoReferrer URL
tnoPage title
wnoViewport width
propsnoCustom object (any JSON)
sidnoSession ID (auto-generated if omitted)

Response

202 Accepted
(empty body)

Returns 202 immediately — event is queued. Batch multiple events by sending an array.

2 Query stats

GET /api/canopy/stats — requires auth (dashboard session). Returns aggregated counts.

Query params

ParamTypeDescription
sitestringSite ID (required)
rangestring7d (default) | 24h | 30d
groupBystringday | hour | path | referrer | event

Example response

GET /api/canopy/stats?site=canopy_example_com&range=7d

{
  "site": "canopy_example_com",
  "range": "7d",
  "totals": {
    "visitors": 12400,
    "pageviews": 28700,
    "events": 11200,
    "uniques": 8400
  },
  "series": [
    { "day": "2024-01-15", "visitors": 1800, "pageviews": 4200 },
    { "day": "2024-01-16", "visitors": 1920, "pageviews": 4500 }
  ],
  "topPaths": [
    { "path": "/", "views": 4200, "uniques": 3100 },
    { "path": "/pricing", "views": 2800, "uniques": 2100 }
  ],
  "topReferrers": [
    { "ref": "https://newsletter.example.com", "count": 1200 }
  ]
}

3 Webhooks

Subscribe to funnel drops, thresholds, anomalies. POST /api/canopy/webhooks (auth required).

Event types

funnel.drop
Funnel conversion drops > threshold
threshold.breach
Metric exceeds configured limit
anomaly.detected
Unusual traffic pattern detected
site.verified
Domain verified via DNS

Payload

{
  "event": "funnel.drop",
  "site": "canopy_example_com",
  "timestamp": "2024-01-15T14:32:00.000Z",
  "data": {
    "funnel": "checkout",
    "steps": ["view", "cart", "checkout"],
    "conversion": 0.021,
    "previous": 0.033,
    "drop": 0.36
  }
}

4 Site verification

Prove domain ownership via DNS TXT record. Unlocks verified badge and webhook trust.

Verify endpoint
GET /api/verify?site=canopy_example_com

{
  "site": "canopy_example_com",
  "status": "pending",
  "record": "canopy-site=abc123xyz",
  "instructions": "Add TXT record @ with value above"
}

After DNS propagates, re-check — status becomes verified and badge appears on dashboard.

5 Errors

CodeMeaning
400Missing required field (s or n)
404Unknown site ID
422Invalid JSON or field validation failed
429Rate limited (per-site, generous)
500Internal error — check logs

Start sending events

No API keys for ingestion. Just POST to your endpoint.