---
title: "Subscribe to bid-outcome webhooks"
method: POST
path: "/api/v1/webhooks"
tags: ["Outcomes"]
---

# Subscribe to bid-outcome webhooks

`POST /api/v1/webhooks`

## Request

- Base URL: `https://www.upgradeagent.ai`
- URL: `https://www.upgradeagent.ai/api/v1/webhooks`
- Auth: one of:
  - OAuth 2 (authorization code, authorization URL `https://www.upgradeagent.ai/api/oauth/authorize`, token URL `https://www.upgradeagent.ai/api/oauth/token`, scopes: `mcp`)
  - HTTP bearer

Register an HTTPS endpoint to receive signed events when an offer's status changes (and when checkout completes). The response includes the signing `secret` exactly once. Deliveries are retried 3 times inline, then up to 8 more times over ~21h with exponential backoff; 20 consecutive failures disable the webhook. At most 10 active webhooks per caller.

## Request body

- WebhookRequest
  - `url` string, required: HTTPS endpoint on a public host. http, localhost, private/link-local addresses and credentials in the URL are rejected (400 WEBHOOK_URL_REJECTED).
  - `events` string[]: Events to receive. Default: all.
  - `quoteId` string: Scope to one quote this caller owns (pending quotes allowed). Omit to receive events for every quote the caller owns.

## Response `201`

Webhook created — store `secret` now.

- WebhookCreated
  - `id` string, required
  - `url` string, required
  - `events` string[], required
  - `quoteId` string, nullable, required: Bound quote, or null for all of the caller's quotes.
  - `active` boolean, required: False once auto-disabled after 20 consecutive failed deliveries.
  - `createdAt` string, required
  - `lastDeliveryAt` string, nullable, required: Last successful (2xx) delivery.
  - `failureCount` integer, required: Consecutive failed deliveries.
  - `secret` string, required: The signing secret — shown ONCE. Store it; it is kept encrypted and never returned again.
  - `signing` WebhookSigning, required
    - `header` 'X-UpgradeAgent-Signature', required: Signature header name.
    - `format` string, required: `t=<unix seconds>,v1=<hex HMAC-SHA256(secret, `${t}.${rawBody}`)>`
    - `toleranceSeconds` integer, required: Reject signatures whose t is more than this far from now (300).
    - `eventHeader` 'X-UpgradeAgent-Event', required
    - `idempotencyHeader` 'X-UpgradeAgent-Idempotency-Key', required
    - `docs` string, required: Verification guide.

## Other responses

- `400`: URL rejected (WEBHOOK_URL_REJECTED: not https, private/loopback host, credentials in URL) or unknown events.
- `401`: Missing, invalid, expired, or revoked bearer token. The WWW-Authenticate challenge points at the OAuth protected-resource metadata.
- `404`: quoteId unknown or owned by another caller.
- `409`: Webhook limit reached (WEBHOOK_LIMIT).
- `429`: Per-caller rate limit exceeded.
- `503`: Webhook store unavailable on this deployment.

---

[API](https://skmtc.dev/upgradeagent/apis/upgrade-agent-rest-api.md) · [All operations](https://skmtc.dev/upgradeagent/apis/upgrade-agent-rest-api/llms.txt) · [OpenAPI document](https://skmtc.dev/upgradeagent/apis/upgrade-agent-rest-api/revisions/fbed715712c1?raw)
