Skip to main content
Home›Docs›Webhooks›Webhooks API
Webhooks

Webhooks API

Create, list, and delete webhook subscriptions, and verify endpoint domains, through the REST API.

Webhooks API

Webhooks are HTTP push subscriptions that POST event notifications to a URL you control when analysis and report jobs complete. These endpoints let you manage subscriptions programmatically: register URLs, list and delete them, and verify ownership of the receiving domain. For concepts and setup walkthroughs, see the guides linked at the bottom of this page.

All endpoints on this page require the workspace admin role (workspace owners always qualify). Requests from other workspace roles are rejected with 403 Admin access required for this workspace.

Base URL: https://api.perceive8.com. Authenticate with X-API-Key: pk_live_... or Authorization: Bearer <jwt-or-key>.

POST /v1/webhooks

Create a webhook subscription for the authenticated workspace. A signing secret is generated server-side (64 hex characters) and stored on the webhook; it is used to sign every delivery but is not returned by any endpoint. Creating a webhook also creates (or refreshes) a domain-verification record for the URL's domain and returns it alongside the webhook; if that record cannot be created, domain_verification is null and the webhook is still created.

Request body

Field Type Required Description
url string yes HTTPS endpoint that receives event POSTs (max 2048 chars)
events array of strings no Event names to subscribe to. Defaults to ["analysis.completed"]
{
  "url": "https://yourapp.example.com/webhooks/perceive8",
  "events": ["analysis.completed", "report.completed"]
}

Response 200 OK

webhook contains the created subscription; domain_verification contains the DNS instructions for the URL's domain (see Domain verification).

{
  "webhook": {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "user_id": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed",
    "url": "https://yourapp.example.com/webhooks/perceive8",
    "events": ["analysis.completed", "report.completed"],
    "is_active": true,
    "domain_verified": false,
    "created_at": "2026-08-19T10:00:00Z",
    "last_triggered_at": null
  },
  "domain_verification": {
    "id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
    "domain": "yourapp.example.com",
    "token": "dGhpcy1pcy1hbi1leGFtcGxlLXRva2Vu",
    "status": "pending",
    "expires_at": "2026-08-22T10:00:00Z",
    "txt_record_name": "_perceive8-verify.yourapp.example.com",
    "txt_record_value": "perceive8-verify=dGhpcy1pcy1hbi1leGFtcGxlLXRva2Vu"
  }
}
curl -X POST https://api.perceive8.com/v1/webhooks \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.example.com/webhooks/perceive8",
    "events": ["analysis.completed", "report.completed"]
  }'

GET /v1/webhooks

List all webhook subscriptions for the authenticated workspace.

Response 200 OK — array of webhook objects:

Field Type Description
id uuid Webhook identifier
user_id uuid Internal user that created the webhook
url string Delivery endpoint
events array of strings Subscribed event names
is_active boolean Inactive webhooks receive no deliveries
domain_verified boolean Whether the URL's domain has been verified
created_at datetime Creation timestamp
last_triggered_at datetime | null Last successful (2xx) delivery timestamp
curl https://api.perceive8.com/v1/webhooks \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx"

DELETE /v1/webhooks/{webhook_id}

Delete a webhook. Deletion is immediate; the endpoint stops receiving events.

Parameters

Name In Type Description
webhook_id path uuid Webhook identifier

Response 204 No Content — empty body. Returns 404 {"detail": "Webhook not found"} if the webhook does not exist in the authenticated workspace.

curl -X DELETE https://api.perceive8.com/v1/webhooks/3fa85f64-5717-4562-b3fc-2c963f66afa6 \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx"

Domain verification

Deliveries are only sent to webhooks whose URL domain has been verified (domain_verified: true); deliveries to unverified domains are skipped. Verification works by publishing a DNS TXT record and asking Perceive8 to check it:

  1. POST /v1/webhooks/verify-domain with the webhook URL → returns a token and the exact TXT record to publish. (This also happens automatically when you create a webhook.)
  2. Publish the TXT record _perceive8-verify.<domain> with value perceive8-verify=<token> at your DNS provider.
  3. POST /v1/webhooks/confirm-domain with the verification_id → Perceive8 performs the DNS lookup and, on a match, marks the domain verified.

The token expires after 72 hours. Requesting verification again for the same domain returns the existing record if already verified, or refreshes the token and expiry (status reset to pending) otherwise. When a domain is confirmed, all webhooks in the workspace whose URL contains that domain are marked domain_verified: true.

POST /v1/webhooks/verify-domain

Initiate (or refresh) domain ownership verification for a webhook URL.

Request body

Field Type Required Description
url string yes Webhook URL; must be http/https with a valid hostname
{
  "url": "https://yourapp.example.com/webhooks/perceive8"
}

Response 200 OK

Field Type Description
id uuid Verification record identifier — pass it to confirm-domain
domain string Hostname extracted from the URL
token string Ownership token to publish in DNS
status string pending, verified, or expired
expires_at datetime Token expiry (72 hours after issuance)
txt_record_name string TXT record name to create: _perceive8-verify.<domain>
txt_record_value string TXT record value to publish: perceive8-verify=<token>

Returns 422 {"detail": "Invalid URL: cannot extract domain"} if no hostname can be parsed from url.

curl -X POST https://api.perceive8.com/v1/webhooks/verify-domain \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://yourapp.example.com/webhooks/perceive8"}'

POST /v1/webhooks/confirm-domain

Perform the DNS TXT lookup and confirm domain ownership. On success, the record's status becomes verified and all workspace webhooks on that domain are marked domain_verified: true.

Request body

Field Type Required Description
verification_id string (uuid) yes id returned by verify-domain or by webhook creation
{
  "verification_id": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"
}

Response 200 OK

{
  "verified": true,
  "message": "Domain verified successfully"
}

verified is false — with a message explaining why — when the record is not found, the token has expired ("Verification token has expired; please request a new one"), no TXT records exist for _perceive8-verify.<domain>, the expected value is not among them, or the DNS lookup fails. An already-verified domain returns verified: true with "Domain already verified".

GET /v1/webhooks/domains

List all domain-verification records for the authenticated workspace.

Response 200 OK — array of domain-verification objects with the same fields as verify-domain (id, domain, token, status, expires_at, txt_record_name, txt_record_value).

curl https://api.perceive8.com/v1/webhooks/domains \
  -H "X-API-Key: pk_live_xxxxxxxxxxxx"

Events

Subscribe to event names in the events array when creating a webhook. The following events are emitted by the platform:

Event When sent Payload fields
analysis.completed An audio-analysis pipeline finishes successfully analysis_id (string), status (string, "completed")
report.completed A report finishes generating for an analysis report_id (string uuid), analysis_id (string), status (string, "COMPLETED")

Example analysis.completed delivery body:

{
  "analysis_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed"
}

Delivery and signatures

Each event is delivered as an HTTP POST with the JSON payload as the raw body. A webhook receives a delivery only when it is active (is_active: true), its events list contains the event, and its domain is verified. On a 2xx response, the webhook's last_triggered_at is updated.

Header Description
X-Perceive8-Signature sha256=<hex> — HMAC-SHA256 of the raw request body, keyed with the webhook's signing secret
X-Perceive8-Event Event name, e.g. analysis.completed
Content-Type application/json

Verify deliveries by computing HMAC-SHA256 over the exact raw request body with your signing secret and comparing it (constant-time) against the hex digest in X-Perceive8-Signature. See the verification guide linked below for sample code. Delivery uses a 10-second timeout; your endpoint should respond quickly and process asynchronously.

See also