Sandbox

Webhook simulator — deliver one signed mock event to your registered webhook_url

Fires ONE deterministic mock change event at the calling account's most recently created ACTIVE webhook subscription and returns the delivery result inline — the full round trip (receiver status code, response time, signature header name, delivery log row id) in a single call. Built for developers evaluating the Accounts Monitor / change feed who need to test their receiver TODAY instead of waiting for a real change to ride the cron pipeline.

The delivery goes through the UNCHANGED production delivery library: the webhook URL is SSRF-re-validated immediately before the request (private / loopback / metadata targets are blocked with error_class: "ssrf_blocked"), DNS is pinned to the validated address, 3xx redirects are never followed, the receiver has 10 seconds to answer, and the body is signed with the SAME Stripe-style x-apier-signature HMAC header real deliveries carry (t=<unix_seconds>,v1=<hex_hmac>, HMAC input <timestamp>.<raw_body>, keyed with the plaintext secret returned once at subscription creation). A receiver that verifies the simulator's signature verifies production's.

Three event_type values, each mapping to one FIXED mock change row (deterministic — byte-identical change object on every call; only delivered_at and the echoed correlation_id vary): accounts_filed mirrors the real Accounts Monitor emitter (source brreg, entity_type annual_accounts); capability_changed mirrors the Altinn schema poller (source altinn, entity_type schema); deadline_elapsed is a synthetic rehearsal of a deadline-status flip (source skatteetaten, entity_type deadline, pending → overdue). The event subject is the reserved sandbox scenario org 999111114 — never a real company.

The attempt is recorded in the append-only webhook_deliveries log tagged is_sandbox: true with NO backing changes row (the real change archive is never polluted with synthetic events), and the cron delivery queue is NEVER touched — the simulator delivers inline, exactly once, attempt_number: 1, no retries.

AUTH — dual, like the other authenticated sandbox mirrors: a real API key OR the synthetic apier_sandbox_test_<suffix> bearer. Note the synthetic bearer cannot own a subscription (subscriptions require a real key), so it deterministically receives the same helpful 404 an unsubscribed real key gets. The endpoint returns 200 even when the receiver rejects the delivery — the SIMULATION completed; the delivery outcome (delivered, http_status, error_class) is the data you asked to see.

post/api/v1/sandbox/subscriptions/test

Request

  • Base URL: https://www.apier.no
  • URL: https://www.apier.no/api/v1/sandbox/subscriptions/test
  • Auth: one of:
    • HTTP bearer
    • HTTP bearer

Query parameters

simulate_error'missing_delegation' | 'invalid_token' | 'validation_error' | 'scope_missing'

Error simulation for agent testing (the four canonical tokens). A valid token short-circuits BEFORE any subscription lookup, outbound delivery, or log write and returns the canned production-shaped explainer envelope: missing_delegation → 403 AUTH_MISSING_DELEGATION; invalid_token → 401 AUTH_EXPIRED_TOKEN; validation_error → 400 VALIDATION_FAILED; scope_missing → 403 SCOPE_MISSING. Unknown values fail 400. The upstream-failure tokens other sandbox surfaces accept (altinn_timeout, invalid_certificate, malformed_payload, upstream_5xx) are deliberately absent: this route's one outbound call goes to YOUR OWN receiver, never a government upstream, so a canned government failure would claim a failure mode this surface structurally cannot have.

Headers

Idempotency-Keystring required

REQUIRED for contract parity with the other sandbox write-side endpoints (same posture as /api/v1/sandbox/actions/execute): the header is validated at the boundary (1-255 printable ASCII; missing → 400 VALIDATION_FAILED with details.field: 'Idempotency-Key') but the simulator deliberately does NOT deduplicate — re-sending a test event is the entire point of a simulator, and every call fires a fresh delivery with a fresh delivery-log row. SDK retry code paths that always attach the header work unchanged against this surface.

Request body

event_type'capability_changed' | 'deadline_elapsed' | 'accounts_filed' required

Which fixed mock change event to synthesize and deliver. accounts_filed mirrors the real Accounts Monitor accounts.updated emission (the one production event type at v1) — use it to validate an Accounts Monitor receiver end-to-end. capability_changed and deadline_elapsed rehearse the same payload envelope with other source/entity_type combinations so filter-driven receivers can exercise their routing before those emitters ship. Anything else fails 400 VALIDATION_FAILED (strict schema — unknown body keys are rejected too, never silently ignored).

Response

The simulation ran to completion — read data.delivered for the receiver's verdict. delivered: true means the receiver answered 2xx; delivered: false carries the failure classification from the production delivery library (error_class: receiver 4xx/5xx → unknown with the status in http_status; SSRF-blocked target → ssrf_blocked with http_status: null; plus timeout, redirect_blocked, dns_failure, tls_failure, network_error, body_too_large). webhook_delivery_id is the append-only webhook_deliveries row recording the attempt (sandbox-tagged); null only if the best-effort log write failed — the delivery itself still happened as reported. Served Cache-Control: no-store like the whole sandbox surface.

successtrue required

Changes

No recorded changes to this operation across all 1 revision of this API.