Record beacon
/v1/beaconsAdvanced direct server path. Default integrations should render placement.render with the hosted renderer, which sends browser beacons automatically to /public/wrapper/v1/beacons. Direct beacon writes are for server-rendered, custom-rendered, or QA validation flows; they require the sensitive asset_token returned with the placement or decision and are idempotent by beacon_id.
AUTH
CONTENT TYPE
STATUS
Request parameters
- beacon_id
- string
- Required
- Idempotency key for this beacon event.
- slot_id
- string
- Required
- Slot associated with the rendered decision.
- asset_token
- string
- Required
- Sensitive asset token issued with the placement response, usually placement.asset_token or decision.asset_token. Required for direct server /v1/beacons; redact it from logs, screenshots, reports, terminal output, external evidence, and client-visible debug output. Do not commit it, do not confuse it with WAVEBIRD_SECRET_KEY/server secret key or publishable key, and do not expose it unnecessarily to frontend code unless required by the hosted renderer flow.
- event
- string
- Required
- rendered, visible, clicked, completed, play_started, play_completed, or heartbeat.
- occurred_at
- string
- Required
- Fresh ISO timestamp for when the event happened. Generate it at runtime; stale copied sample timestamps can return BEACON_TOO_LATE.
- metadata
- object
- Optional
- Optional measurement metadata for the beacon event.
| Name | Type | Required | Description |
|---|---|---|---|
| beacon_id | string | Required | Idempotency key for this beacon event. |
| slot_id | string | Required | Slot associated with the rendered decision. |
| asset_token | string | Required | Sensitive asset token issued with the placement response, usually placement.asset_token or decision.asset_token. Required for direct server /v1/beacons; redact it from logs, screenshots, reports, terminal output, external evidence, and client-visible debug output. Do not commit it, do not confuse it with WAVEBIRD_SECRET_KEY/server secret key or publishable key, and do not expose it unnecessarily to frontend code unless required by the hosted renderer flow. |
| event | string | Required | rendered, visible, clicked, completed, play_started, play_completed, or heartbeat. |
| occurred_at | string | Required | Fresh ISO timestamp for when the event happened. Generate it at runtime; stale copied sample timestamps can return BEACON_TOO_LATE. |
| metadata | object | Optional | Optional measurement metadata for the beacon event. |
Returns
- ok
- boolean
- True when the beacon request was processed successfully.
- accepted
- boolean
- True when the beacon was accepted.
- duplicate
- boolean
- True when the same beacon_id and event context had already been recorded.
- reason_code
- string
- OK for accepted and duplicate beacons.
- proof_source
- string
- Safe diagnostic source label, for example public_wrapper_renderer for hosted renderer rows or direct_server for advanced direct-server beacon rows.
- proof_eligible
- boolean
- Whether the event currently qualifies as proof. Accepted diagnostics can still be proof_eligible=false.
- billable
- boolean
- Whether the event is billable. Accepted diagnostics and all sandbox/test traffic can still be billable=false.
- non_billable_reason
- string
- Reason an accepted diagnostic is not billable, such as DIRECT_BEACON_NOT_BILLABLE, SANDBOX_NON_BILLABLE, or a geometry reason.
- geometry_reason
- string
- Renderer geometry classification: INSUFFICIENT_VISIBLE_AREA, HIDDEN_OR_NOT_VIEWABLE, OFFSCREEN, RENDERED_SIZE_TOO_SMALL, or NO_RENDERER_GEOMETRY_PROOF.
- contract_exists
- boolean
- Whether the beacon was matched to an internal placement contract for diagnostics/proof evaluation.
- renderer_diagnostic_case
- string
- Safe derived case label for renderer diagnostics, such as clipped_8x1_25, hidden, opacity_zero, ancestor_opacity_zero, offscreen, zero_size, tiny, or normal_visible.
- renderer_geometry_summary
- object
- Safe renderer geometry summary for debugging, including declared, wrapper, target, visible, intersection, opacity, offscreen, cropped, and renderer version fields when available.
- mode
- string
- Safe runtime mode label, such as production-dry-run when production dry-run validation is enabled.
- production_dry_run
- boolean
- True when the event was evaluated under production dry-run mode.
- production_billing_dry_run
- boolean
- True when production billing side effects are suppressed for dry-run validation.
- production_live_approved
- boolean
- False in this dry-run flow. production-live-approved is not used for dry-run QA.
- billing_suppressed
- boolean
- True when dry-run mode suppresses billing side effects.
- dry_run_billable_suppressed
- boolean
- True when proof would otherwise be eligible but billing was suppressed by production dry-run.
- proof_would_be_eligible
- boolean
- True for qualifying renderer proof that would be proof-eligible while remaining non-billable in production dry-run.
| Name | Type | Description |
|---|---|---|
| ok | boolean | True when the beacon request was processed successfully. |
| accepted | boolean | True when the beacon was accepted. |
| duplicate | boolean | True when the same beacon_id and event context had already been recorded. |
| reason_code | string | OK for accepted and duplicate beacons. |
| proof_source | string | Safe diagnostic source label, for example public_wrapper_renderer for hosted renderer rows or direct_server for advanced direct-server beacon rows. |
| proof_eligible | boolean | Whether the event currently qualifies as proof. Accepted diagnostics can still be proof_eligible=false. |
| billable | boolean | Whether the event is billable. Accepted diagnostics and all sandbox/test traffic can still be billable=false. |
| non_billable_reason | string | Reason an accepted diagnostic is not billable, such as DIRECT_BEACON_NOT_BILLABLE, SANDBOX_NON_BILLABLE, or a geometry reason. |
| geometry_reason | string | Renderer geometry classification: INSUFFICIENT_VISIBLE_AREA, HIDDEN_OR_NOT_VIEWABLE, OFFSCREEN, RENDERED_SIZE_TOO_SMALL, or NO_RENDERER_GEOMETRY_PROOF. |
| contract_exists | boolean | Whether the beacon was matched to an internal placement contract for diagnostics/proof evaluation. |
| renderer_diagnostic_case | string | Safe derived case label for renderer diagnostics, such as clipped_8x1_25, hidden, opacity_zero, ancestor_opacity_zero, offscreen, zero_size, tiny, or normal_visible. |
| renderer_geometry_summary | object | Safe renderer geometry summary for debugging, including declared, wrapper, target, visible, intersection, opacity, offscreen, cropped, and renderer version fields when available. |
| mode | string | Safe runtime mode label, such as production-dry-run when production dry-run validation is enabled. |
| production_dry_run | boolean | True when the event was evaluated under production dry-run mode. |
| production_billing_dry_run | boolean | True when production billing side effects are suppressed for dry-run validation. |
| production_live_approved | boolean | False in this dry-run flow. production-live-approved is not used for dry-run QA. |
| billing_suppressed | boolean | True when dry-run mode suppresses billing side effects. |
| dry_run_billable_suppressed | boolean | True when proof would otherwise be eligible but billing was suppressed by production dry-run. |
| proof_would_be_eligible | boolean | True for qualifying renderer proof that would be proof-eligible while remaining non-billable in production dry-run. |
Integration guidance
Hosted renderer beacons vs direct server beacons
Most integrations should use the hosted renderer first. Hosted renderer beacons are sent automatically to /public/wrapper/v1/beacons after placement.render is mounted.
For clip placements, the hosted renderer emits play_started and play_completed. Direct server integrations can send play_started and play_completed to /v1/beacons when they own a custom clip renderer.
For native and banner placements, render/click/visibility beacons use the same issued asset_token; native click handling is attached to the hosted native frame overlay.
Use direct /v1/beacons only for advanced server-rendered, custom-rendered, or QA flows. Direct server beacons should not be used to fake or duplicate renderer events except for explicit idempotency or QA testing.
Direct server beacons always require the issued asset_token from placement.asset_token or decision.asset_token.
Direct server beacons are diagnostic/non-billable by default unless a trusted measurement policy explicitly allows them.
| Path | Endpoint | Caller | Use case | Manual code required |
|---|---|---|---|---|
| Hosted renderer beacons | /public/wrapper/v1/beacons | Wavebird hosted renderer/browser runtime | Default measurement/proof path | No |
| Direct server beacons | /v1/beacons | Publisher server | Advanced server-rendered/custom-rendered/QA path | Yes |
Renderer diagnostic outcomes
Accepted renderer diagnostics do not automatically mean proof eligible or billable. Check proof_eligible and billable separately.
INSUFFICIENT_VISIBLE_AREA means the declared creative exists but the measured visible/intersection area was too small, for example because the slot was clipped, cropped, masked, or mostly outside the viewport.
HIDDEN_OR_NOT_VIEWABLE means the renderer evidence indicates display:none, visibility:hidden/collapse, zero/effective opacity, or a hidden/zero-viewable state.
OFFSCREEN means the renderer evidence indicates the slot is outside the viewport. RENDERED_SIZE_TOO_SMALL means the rendered container itself is below the paid-size contract without a clearer clipping signal.
NO_RENDERER_GEOMETRY_PROOF means proof-required geometry was missing. Sandbox/test traffic remains non-billable even when diagnostics are accepted.
renderer_diagnostic_case is a safe derived label that helps identify the exact renderer row during QA without exposing raw tokens, prompts, or private advertiser policy.
Production dry-run is explicitly non-billable. Create a Server Production Dry-run Key in Dashboard API Keys or use an operator-issued sk_dry_... server key as WAVEBIRD_SECRET_KEY.
Production dry-run is selected by credential class, not by request fields. Do not send production_dry_run, production_billing_dry_run, billing_suppressed, or production_live_approved in request bodies; those names are response, log, or dashboard diagnostics only.
A qualifying renderer proof row can expose mode=production-dry-run, PRODUCTION_DRY_RUN_NON_BILLABLE, production_dry_run=true, production_live_approved=false, billing_suppressed=true, dry_run_billable_suppressed=true, and proof_would_be_eligible=true.
No payout setup is required for production dry-run, and production-live-approved is not used. If no active SSP demand is available, the safe blocker is 409 ssp_not_ready with mode=production-dry-run, production_dry_run=true, production_billing_dry_run=true, billing_suppressed=true, production_live_approved=false, live_billing=false, and billable=false.
| Field | Meaning |
|---|---|
| proof_source | Where the proof/diagnostic evidence came from, such as public_wrapper_renderer or direct_server. |
| proof_eligible | Whether the event qualifies as proof after policy and geometry checks. |
| billable | Whether the event can create billable production value. |
| non_billable_reason | Why the accepted event is not billable. |
| geometry_reason | Renderer geometry classification when geometry prevents proof. |
| contract_exists | Whether an internal placement contract was found. |
| renderer_diagnostic_case | Derived renderer case label, such as clipped_8x1_25, hidden, opacity_zero, offscreen, zero_size, tiny, or normal_visible. |
| renderer_geometry_summary | Safe geometry summary for debugging, without raw tokens or private advertiser policy. |
| production_dry_run | Whether production dry-run mode was active for the event. |
| production_live_approved | False for dry-run QA; production-live-approved is not used. |
| proof_would_be_eligible | Whether qualifying renderer proof would be eligible if billing were not suppressed by dry-run. |
| dry_run_billable_suppressed | Whether production dry-run suppressed billable side effects for otherwise qualifying proof. |
Fresh timestamps and BEACON_TOO_LATE
occurred_at must be close to the real event time. Do not copy old static timestamps from examples.
Generate a fresh timestamp at runtime for every direct server beacon call.
BEACON_TOO_LATE means the event timestamp is too old to be accepted. This commonly happens when testing with copied sample timestamps; use current timestamps for direct server beacon calls.
const occurred_at = new Date().toISOString();asset_token handling
asset_token is required for direct server /v1/beacons. It is issued with the placement response and is usually available as placement.asset_token or decision.asset_token.
Treat asset_token as sensitive proof material. Redact it from logs, screenshots, reports, support tickets, terminal output, external evidence, and client-visible debug output.
Do not commit asset_token, do not confuse it with WAVEBIRD_SECRET_KEY/server secret key or publishable key, and do not expose it unnecessarily to frontend code unless required by the hosted renderer flow.
Errors
unauthorized401Missing auth or asset token.
forbidden403API key or activation token does not match the project that issued the asset_token.
validation_error400Unsupported event name, malformed body, stale occurred_at / BEACON_TOO_LATE, or slot_id/asset_token mismatch. Errors include field paths.
not_found404asset_token was not found or is no longer valid.