Skip to main content

API reference

Webhooks API

Create and manage webhooks programmatically to receive real-time notifications.

List webhooks

GET/v1/webhooks
Response
{
  "success": true,
  "data": {
    "webhooks": [
      {
        "webhook_id": "wh_1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d",
        "url": "https://your-app.com/webhook",
        "description": "Production endpoint",
        "events": ["job.completed", "job.failed"],
        "is_active": true,
        "created_at": "2026-01-15T10:00:00Z",
        "updated_at": "2026-01-15T10:00:00Z",
        "last_triggered_at": "2026-02-03T14:35:42Z",
        "failure_count": 0
      }
    ],
    "count": 1
  }
}

Create webhook

POST/v1/webhooks

Request body

ParameterTypeRequiredDescription
urlstringRequiredHTTPS URL to receive webhooks
eventsstring[]RequiredEvents to subscribe to. Only events with available: true in the catalog can be subscribed — the API rejects the rest
descriptionstringOptionalFree-form label for the webhook
cURL
curl -X POST https://api.kawaa.com/v1/webhooks \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhook",
    "events": ["job.completed", "job.failed"]
  }'

The body accepts only url, events and description; any other key (for example event) returns HTTP 400 naming the supported fields rather than creating the webhook without it.

The response includes the webhook's signing secret — store it to verify the X-Kawaa-Signature header on deliveries. Deliverable events: verification.completed, verification.failed, job.completed, job.failed, credits.low, credits.exhausted, blacklist.detected and dmarc.failure. verification.* events fire for single verifications (POST /v1/verify) — fresh verifications only, since cached results return synchronously; bulk jobs emit job.* events instead. credits.low is delivered at most once per 7 days and credits.exhausted at most once per 24 hours.

Update webhook

PUT/v1/webhooks/{id}

Update an existing webhook. The body accepts url, events, description and is_active (set it to false to pause deliveries without deleting the webhook). Only the fields you send change. The read-only fields a GET returns (webhook_id, created_at, updated_at, last_triggered_at, failure_count) are accepted as no-ops so a GET payload can be sent straight back; any other key returns HTTP 400.

Get webhook

GET/v1/webhooks/{id}

Return one webhook in the same shape as the list entries above. The signing secret is never included — it is shown once on creation and again only by the regenerate call below. An id that belongs to another account is a 404.

Delivery logs

GET/v1/webhooks/{id}/logs

List the deliveries attempted to this webhook, newest first. Logs are kept for 30 days.

Query parameters

ParameterDescription
limitEntries per page (default: 20, max: 100)
offsetEntries to skip (default: 0, max: 1,000)
cursorOpaque cursor from the previous page's cursor, for paging past the offset bound
Response
{
  "success": true,
  "data": {
    "logs": [
      {
        "log_id": "3f6c1a2e-8d4b-4b1f-9a70-5c2e7d1b9f11",
        "event": "job.completed",
        "status": "success",
        "status_code": 200,
        "response_time_ms": 184,
        "request_body": "{\"event\":\"job.completed\",\"data\":{...}}",
        "response_body": "OK",
        "error_message": null,
        "created_at": "2026-02-03T14:35:42.100Z",
        "delivery_type": "event"
      }
    ],
    "total": 1,
    "limit": 20,
    "offset": 0
  }
}

status is success or failed; status_code and response_body are null when no HTTP response was received (timeout, DNS or connection error — see error_message). delivery_type distinguishes real event deliveries from test sends. A failed entry can be re-sent with POST /v1/webhooks/{id}/logs/{log_id}/retry.

Delete webhook

DELETE/v1/webhooks/{id}

Remove a webhook subscription.

Test webhook

POST/v1/webhooks/{id}/test

Send a test event to verify your webhook endpoint is working correctly.

Regenerate secret

POST/v1/webhooks/{id}/secret

Generate a new signing secret for the webhook. The old secret will be immediately invalidated.

Available events

GET/v1/webhooks/events

Get the webhook event catalog. Each event is an object with an available flag — only events with available: true can be subscribed to.

Response
{
  "success": true,
  "data": {
    "events": [
      {
        "name": "job.completed",
        "description": "Triggered when a bulk verification job is completed",
        "category": "jobs",
        "available": true,
        "payload_example": {
          "event": "job.completed",
          "data": {
            "job_id": "job_abc123",
            "total_emails": 1000,
            "summary": { "valid": 800, "invalid": 150, "risky": 50 },
            "completed_at": "2025-01-01T00:00:00Z"
          }
        }
      },
      {
        "name": "verification.completed",
        "description": "Triggered when a single email verification completes",
        "category": "verification",
        "available": true,
        "payload_example": {
          "event": "verification.completed",
          "data": {
            "job_id": "job_abc123",
            "email": "user@example.com",
            "status": "valid",
            "quality_score": 95,
            "verified_at": "2025-01-01T00:00:00Z",
            "credits_used": 1
          }
        }
      }
    ]
  }
}