Testing

Verify a placement from request to rendered ad, including consent, no-fill, and measurement. Start with test credentials, then check production dry-run before enabling billable traffic.

Test safely

Environments and credentials

Test

Use a Server Test Key (sk_test_*) for integration checks. Test traffic is non-billable, including validation and guardrail diagnostics.

Production dry-run

Use a Server Production Dry-run Key (sk_dry_...). Dry-run is selected by credential class and remains non-billable. No payout setup is required.

Live boundary

Before sending billable traffic, complete payout setup and activate live delivery for your project in Dashboard. Billable impressions require verified delivery records.

Secret visibility

Credential classes

Server credentials

Server Test, Production Dry-run, and Live keys are backend-only secrets. Copy the full value when it is created or rotated; Dashboard stores only a masked preview and cannot reveal the original secret later.

Browser credentials

Browser publishable keys are limited to their configured origins and project. They do not replace a server key and must never grant access to billing, payout, or private account operations.

Checklist

Minimum validation path

Check credentials and project

The server key and browser publishable key must belong to the same Test project. Use its Project ID as client_id or WAVEBIRD_CLIENT_ID. In Dashboard API Keys, create or rotate a Server Test Key and copy the full value immediately; masked previews are for identification and cannot authenticate requests.

Key classes and rotation

Exercise no-fill and fill

A filled response should render the selected format. No-fill should leave no empty ad container and must not interrupt the AI task. Use the controlled no-fill request below to test this branch.

Exercise optional fields

Test prompt, slot_hint, request-level consent, and advanced overrides separately. Validation errors include request_id and field paths such as slot_hint.max_width.

Confirm beacons

Check rendered and completion beacons for the formats you actually ship. Billing evidence depends on that path, not just on placement creation.

Server Test Key only

Deterministic Test no-fill

Trigger one controlled no-fill

Call /v1/placements?wait_ms=1500&test_outcome=no_fill with the same valid body you use for a normal Test request. The response is successful and processed, but returns decision.fill: false, placement: null, and test_controlled_no_fill as its no-fill reason.

Keep it outside Production

The control is accepted only with a Server Test Key and remains non-billable. Production, production dry-run, and browser keys cannot use it. Remove the query parameter for ordinary fill testing.

Script Tag

Browser-specific checks

Verify activation against the expected origin, validate consent-required behavior, and confirm that the browser receives only the runtime-safe project config for the active client_id.

Sandbox

Expected negative tests

Beacon validation failures

Intentionally missing asset_token, missing slot_id, invalid event, or stale occurred_at requests should return actionable 400 validation errors in sandbox tests.

A stale timestamp can return BEACON_TOO_LATE. Generate a fresh timestamp for every direct server beacon with new Date().toISOString().

Consent validation failures

Invalid consent purposes should return field-level validation errors. These are expected negative tests when deliberately triggered and should not be treated as production integration failures.

Hosted renderer first

Default integrations should rely on hosted renderer beacons sent to /public/wrapper/v1/beacons. Direct server /v1/beacons is an advanced QA or custom-rendering path.

Direct beacon token handling

Direct server beacons require the sensitive asset_token from placement.asset_token or decision.asset_token. Redact it from logs, screenshots, reports, and client-visible debug output.

Sandbox

Renderer proof diagnostics

Hosted renderer beacons are accepted for sandbox QA even when they are not proof-eligible or billable. Dashboard logs may expose safe diagnostic fields such as proof_source=public_wrapper_renderer, proof_eligible=false, billable=false, non_billable_reason, geometry_reason, renderer_diagnostic_case, contract_exists=true, and renderer_geometry_summary.

CaseExpected reasonUse in QA
tinyINSUFFICIENT_VISIBLE_AREAPositive but too-small visible geometry, such as a 1x1 diagnostic slot.
clipped_8x1_25INSUFFICIENT_VISIBLE_AREAA clipped renderer row with visible/intersection geometry below the paid contract.
hidden or opacity_zeroHIDDEN_OR_NOT_VIEWABLECSS-hidden or transparent renderer evidence that must remain non-billable.
offscreenOFFSCREENRenderer evidence outside the viewport or intersection path.

Pre-live

Production dry-run contract

Use the dry-run server key

Production dry-run is a public pre-live validation mode selected by credential class, not by a request-body flag. Create a Server Production Dry-run Key in Dashboard API Keys, or request one from your wavebird contact. Set its sk_dry_... value as WAVEBIRD_SECRET_KEY for normal server-side /v1/placements calls. Do not send undocumented production_dry_run, production_billing_dry_run, billing_suppressed, or production_live_approved fields in request bodies; those names are response, log, or dashboard diagnostics only.

Check project activation

If live delivery is not activated for your project, use a Server Test Key to validate the integration. Use a Production Dry-run Key when it is available in Dashboard; it verifies the delivery path without billing.

Expect safe blocked responses

A dry-run placement with no active SSP readiness should fail closed with 409 ssp_not_ready. The expected response/log fields include 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.

Check renderer evidence

Qualifying hosted renderer proof in dry-run should report 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.

Live billing stays separate

Use test or dry-run credentials for these checks. Do not click real ads for testing. A successful dry-run verifies delivery, not live billing. The mode is production-dry-run, not production-live-approved.

Need help with your integration?

Share the affected endpoint, request ID, and the behavior you expected. Leave out keys and user content.

Contact the team