Skip to main content
Conto POSTs signed JSON events to your HTTPS endpoint.

Two kinds of webhooks

Conto has two webhook systems. This page covers event webhooks. Both sign with HMAC-SHA256 and send X-Conto-Signature, but they sign different input, so each needs its own verifier.

Test a local handler

With the Conto CLI installed, use the same development signing secret in your handler and terminal:
This sends one signed synthetic payment.confirmed event with data.test: true and a test_ payment ID. It reports the HTTP status and latency, creates no Conto payment, and requires no API key. The command accepts only loopback URLs and does not follow redirects. It tests your handler’s signature and payload processing, not whether hosted delivery can reach your endpoint. If you installed the package globally, conto webhooks test <url> runs the same command.

Setup

  1. Go to Settings > Event Delivery in the dashboard
  2. Enter your HTTPS endpoint URL
  3. Copy the generated signing secret. Your handler uses it to verify payloads
Webhook URLs must use HTTPS. HTTP, loopback hosts, and private IP ranges are blocked for security (SSRF protection).

Event types

Alerts are not sent to this webhook. To receive HIGH and CRITICAL alerts off the dashboard, subscribe a webhook notification channel to alert.raised.

Governance events for SIEM and GRC

policy.*, approval.*, and governance.approval.decided stream policy and approval-decision activity to your webhook for your own audit trail. Payloads differ by event family:
  • Policy events (policy.created / updated / deleted) carry policyId, name, and policyType, never the underlying rule values. policy.created also includes scope, priority, and rulesCount. policy.updated includes isActive.
  • Approval events (approval.approved / approval.denied) carry approvalRequestId, paymentRequestId, amount, and decision (APPROVED or DENIED). Agent callback deliveries add agentId.
  • governance.approval.decided (separation-of-duties decisions on sensitive changes) carries governanceApprovalRequestId, action, resource, resourceId, and decision.
They are delivered best-effort after the change commits, so a delivery failure never blocks the change itself.

Payload format

Every webhook POST includes these headers and a JSON body:

Headers

Body

Organization webhook deliveries add organizationId to data. Agent callback deliveries add agentId instead.

Verifying signatures

Conto signs every payload with your webhook secret using HMAC-SHA256. Verify the signature to confirm the request came from Conto. These event webhooks sign the raw request body only. Notification-channel webhooks sign different input, so they need their own verifier. See two kinds of webhooks.
The same rule applies in other frameworks: verify the exact raw request body before you parse it.

Retry behavior

Each delivery gets up to 3 attempts in total. An attempt fails if your endpoint returns a non-2xx status or doesn’t respond within 10 seconds. Conto retries only failures that can succeed on replay: a network error, a timeout, or an HTTP 408, 429, or 5xx response. Any other status (for example 400, 401, or 404) ends the delivery after that attempt. Every attempt carries the same X-Conto-Delivery-Id (also deliveryId in the body). Use it to dedupe a delivery you already processed.

Agent callback URLs

An agent can also have its own callbackUrl, set with POST /api/agents and changed or cleared with PATCH /api/agents/{id}. Events for that agent then go to both the organization URL and the callback URL, with the same payload format and signature headers. Policy and governance events go only to the organization webhook. Agent callbacks are signed with the same organization signing secret as the organization webhook. The first time you configure a callback URL (or an organization webhook URL), the response includes webhookSecret once. Store it to verify the X-Conto-Signature on callback deliveries. If you did not capture it, rotate it from Settings > Event Delivery and update your receiver. Authenticated agent reads return webhookConfigured and the configured callbackUrl. Responses replace query and fragment values with REDACTED because callback URLs commonly carry credentials. Send the full URL again when rotating those values.

Settlement mode in payment events

The payment.executed payload includes settlementMode: test for simulated execution or live for an onchain transfer, including testnet. Simulated events omit transactionHash, so use the payment ID to read status. A payment.confirmed event represents onchain confirmation and reports live. Do not treat a simulated execution event as proof that funds moved.