HookDeploy

The Requests API lets you list and retrieve captured webhook metadata for an endpoint programmatically.

List requests

GET /v1/endpoints/:id/requests

Returns captured requests for an endpoint, newest first.

curl -s "https://api.hookdeploy.dev/v1/endpoints/ENDPOINT_ID/requests?limit=10" \
  -H "Authorization: Bearer hd_live_YOUR_KEY"

Query parameters:

ParamDefaultMaxDescription
limit50100Number of requests to return
beforeRequest UUID cursor for pagination

Response:

{
  "data": [
    {
      "id": "770e8400-e29b-41d4-a716-446655440002",
      "endpoint_id": "550e8400-e29b-41d4-a716-446655440000",
      "organization_id": "660e8400-e29b-41d4-a716-446655440001",
      "method": "POST",
      "headers": {
        "content-type": "application/json",
        "user-agent": "Stripe/1.0"
      },
      "query": {},
      "content_type": "application/json",
      "body_size_bytes": 1024,
      "source_ip": "1.2.3.4",
      "created_at": "2025-05-23T12:00:00Z",
      "forward_url": "https://example.com/webhooks/stripe",
      "forward_attempted_at": "2025-05-23T12:00:01Z",
      "forward_status_code": 200,
      "forward_response_time_ms": 87,
      "forward_error": null,
      "body_url": null
    }
  ],
  "pagination": {
    "next_cursor": "770e8400-e29b-41d4-a716-446655440002"
  }
}

When next_cursor is null, you’ve reached the end of the list.

Cursor pagination

HookDeploy uses cursor-based pagination, not offset/limit pages. This keeps performance consistent as your request history grows.

First page:

curl -s "https://api.hookdeploy.dev/v1/endpoints/ENDPOINT_ID/requests?limit=50" \
  -H "Authorization: Bearer hd_live_YOUR_KEY"

Next page — pass the next_cursor value as before:

curl -s "https://api.hookdeploy.dev/v1/endpoints/ENDPOINT_ID/requests?limit=50&before=770e8400-e29b-41d4-a716-446655440002" \
  -H "Authorization: Bearer hd_live_YOUR_KEY"

Repeat until next_cursor is null.

Pagination walks backward in time — before returns requests older than the given ID. There is no forward pagination (newer than X) because the default listing already returns newest first.

Pagination example in a loop

CURSOR=""
while true; do
  if [ -z "$CURSOR" ]; then
    URL="https://api.hookdeploy.dev/v1/endpoints/ENDPOINT_ID/requests?limit=50"
  else
    URL="https://api.hookdeploy.dev/v1/endpoints/ENDPOINT_ID/requests?limit=50&before=$CURSOR"
  fi

  RESPONSE=$(curl -s "$URL" -H "Authorization: Bearer hd_live_YOUR_KEY")
  echo "$RESPONSE" | jq '.data[].id'

  CURSOR=$(echo "$RESPONSE" | jq -r '.pagination.next_cursor')
  if [ "$CURSOR" = "null" ]; then break; fi
done

Get request

GET /v1/endpoints/:id/requests/:requestId

Returns a single request with full forward/replay status fields.

curl -s "https://api.hookdeploy.dev/v1/endpoints/ENDPOINT_ID/requests/REQUEST_ID" \
  -H "Authorization: Bearer hd_live_YOUR_KEY"

Response includes:

{
  "data": {
    "id": "770e8400-e29b-41d4-a716-446655440002",
    "method": "POST",
    "headers": { "content-type": "application/json" },
    "body_size_bytes": 1024,
    "source_ip": "1.2.3.4",
    "created_at": "2025-05-23T12:00:00Z",
    "body_url": null,
    "body_note": "Request body is not available via the API yet. View the body in the HookDeploy dashboard."
  }
}

Request body access

Request bodies are stored in Cloudflare R2, not in the API response. The body_r2_key internal field is never exposed.

  • body_url — Reserved for signed URL access in a future version. Currently always null.
  • body_note — Explains that bodies must be viewed in the dashboard for now.

View the full body in the dashboard inspector at app.hookdeploy.dev.

Forward fields

When auto-forwarding is configured, list and get responses include forward attempt metadata:

FieldDescription
forward_urlTarget URL at time of forward
forward_attempted_atISO 8601 timestamp
forward_status_codeHTTP status from your server, or null
forward_response_time_msRound-trip milliseconds
forward_errorError string if connection failed

Security

  • Requests are scoped to the authenticated organization via API key
  • body_r2_key is never returned — R2 paths are internal only
  • Payload contents are never logged in application logs

Next steps