Notification Channels
Notification channels send approval requests and webhook lifecycle events to external platforms. Approvers can approve or reject directly from their email inbox, Slack workspace, Telegram chat, or WhatsApp conversation. Webhook channels can also receive machine-readable payment execution and Conto Pay request events for agents and back-office systems.How It Works
submitApprovalDecision() path. Audit logs, atomic counters, webhook delivery, and race-condition safety all apply regardless of channel.
Supported Channels
| Channel | Delivery | How Approvers Act |
|---|---|---|
| Rich HTML via Resend | Click Approve/Reject button links | |
| Slack | Block Kit message with buttons | Click interactive action buttons |
| Telegram | Message with inline keyboard | Tap inline keyboard buttons |
| Interactive button message | Tap reply buttons | |
| Webhook | JSON POST with tokens | POST tokens back to Conto API |
Setting Up Channels
Go to Settings > Channels in the Conto dashboard, or use the REST API.Choose a channel type
Click Add Channel and select the platform: Email, Slack, Telegram, WhatsApp, or Webhook.
Configure credentials
Each channel type requires different configuration:
Webhook targets must resolve to public addresses. Conto rejects loopback, private, link-local, and other internal-only destinations. In production, webhook channels must use HTTPS.
| Channel | Required Config |
|---|---|
| Comma-separated recipient email addresses | |
| Slack | Bot token (xoxb-...) and channel ID |
| Telegram | Bot token, chat ID, and optional webhook secret token |
| Phone number ID, access token, recipient numbers | |
| Webhook | HTTPS URL and a signing secret (secret in config) |
Select event types
Choose which events trigger notifications:
| Event | When It Fires | Notes |
|---|---|---|
approval.requested | New payment needs approval | Available on all channel types |
approval.decided | Someone approved or rejected | Available on all channel types |
approval.escalated | Request escalated after timeout | Available on all channel types |
approval.expired | Request expired without resolution | Available on all channel types |
payment.executed | Payment is submitted onchain | WEBHOOK channels only |
conto_pay.request.received | A hosted Conto Pay request is sent to the payer | WEBHOOK channels only |
conto_pay.request.paid | A hosted Conto Pay request is paid | WEBHOOK channels only |
conto_pay.request.rejected | A hosted Conto Pay request is rejected | WEBHOOK channels only |
conto_pay.request.expired | A hosted Conto Pay request expires | WEBHOOK channels only |
Channel Configuration Details
Email
Uses Resend to deliver rich HTML emails. Each eligible approver receives their own email with unique Approve and Reject buttons.Config fields:
recipients- List of email addresses. Only addresses matching eligible approvers receive actionable emails.
Slack
Slack
Requires a Slack app with the
chat:write bot scope. Messages use Block Kit with payment details and interactive Approve/Reject buttons.Config fields:botToken- Your Slack app’s bot token (xoxb-...)channelId- The Slack channel ID to post messages to
- Create a Slack app at api.slack.com/apps
- Add the
chat:writebot scope - Install the app to your workspace
- Set the interactivity request URL to
https://conto.finance/api/webhooks/slack - Set
SLACK_SIGNING_SECRETin your Conto environment
Telegram
Telegram
Uses the Telegram Bot API to send messages with inline keyboard buttons.Config fields:
botToken- Your Telegram bot token from @BotFatherchatId- The chat or group ID to send messages tosecretToken- Optional webhook secret. When set, Conto requires Telegram to send the matchingx-telegram-bot-api-secret-tokenheader on every callback.
- Create a bot via @BotFather
- Set the webhook URL:
https://api.telegram.org/bot{token}/setWebhook?url=https://conto.finance/api/webhooks/telegram - If you configure
secretToken, include Telegram’ssecret_tokenoption when callingsetWebhook - Add the bot to your group chat
chatId. If
secretToken is set, Telegram callbacks must also include the matching
secret header before approval tokens are processed.When an approver taps a button, the message updates to show the result.WhatsApp
Uses the WhatsApp Cloud API to send interactive button messages.Config fields:
phoneNumberId- Your WhatsApp Business phone number IDaccessToken- Permanent access token from MetarecipientNumbers- Phone numbers in international format (e.g.,+1234567890)
- Register at developers.facebook.com
- Create a WhatsApp Business app
- Set the webhook URL to
https://conto.finance/api/webhooks/whatsapp - Set
WHATSAPP_APP_SECRETandWHATSAPP_VERIFY_TOKENin your Conto environment - Subscribe to the
messageswebhook field
Webhook
Webhook
Sends a signed JSON payload to any HTTPS endpoint. Use this for custom integrations that need to review and submit approval decisions.Config fields:To submit a decision, POST the token back to the
url- Your HTTPS endpoint URLsecret- Signing secret for HMAC verification (required;signingSecretandwebhookSecretare accepted aliases)
X-Conto-Signature header carries an HMAC-SHA256 of
${timestamp}.${rawBody} computed with your channel secret. Verify it before trusting the
payload.Validation rules:- The destination must resolve to a public IP address
- Private, loopback, link-local, and
.internal/.localhosts are rejected - In production, only
https://webhook targets are accepted
actionUrl:Conto Pay Lifecycle Webhooks
Webhook channels can subscribe to hosted Conto Pay request lifecycle events:conto_pay.request.received, conto_pay.request.paid, conto_pay.request.rejected, and
conto_pay.request.expired.
The received event is delivered to the payer organization. Terminal outcomes (paid,
rejected, and expired) are delivered to both the payer and payee organizations when they have
matching active webhook channels.
Each Conto Pay webhook payload includes absolute hosted links for the request review page and the
payer action page. These match the copyable links shown in the Conto Pay activity inbox and hosted
request review screens, so external systems and human operators can refer to the same URL.
request.direction to render the event from the receiving organization’s point of view:
incoming means the organization is the payer, while outgoing means the organization created the
request and is waiting on the payer.
REST API
Manage channels programmatically:Action Token Security
Action tokens are the core security mechanism for external approvals.- 32 bytes of cryptographic randomness, base64url-encoded
- Protected at rest. Plaintext tokens are not retained after issuance
- One-time use. Tokens cannot be reused after a decision is recorded
- Time-limited. Tokens expire when the approval request expires (default 24 hours)
- Per-user, per-action. Each approver gets separate Approve and Reject tokens
- Full audit trail. Every decision records the channel, token ID, IP address, and user agent
Environment Variables
| Variable | Required For | Description |
|---|---|---|
RESEND_API_KEY | Resend API key for sending emails | |
SLACK_SIGNING_SECRET | Slack | Slack app signing secret for webhook verification |
WHATSAPP_APP_SECRET | Meta app secret for webhook signature verification | |
WHATSAPP_VERIFY_TOKEN | Token for Meta webhook verification challenge |
Webhook Payload Validation
Inbound webhook payloads from Slack, Telegram, and WhatsApp are validated against typed Zod schemas before processing. Malformed payloads are rejected with a400 response and never reach handler logic. Signature verification
(HMAC) still runs first for all three providers regardless of payload shape.
Delta Verification Channel (pilot)
Delta is a guided pilot that routes payment approvals through an external invoice-verification service. It is not a self-serve channel type: Conto activates it for your organization during onboarding as a standardWEBHOOK channel with additional Delta configuration. For access,
onboarding inputs, and activation details, see Delta Verification Setup; to
validate the live flow end to end, see Delta Smoke Test.
Two things differ from a standard webhook channel:
1. Enriched payloads. When approval.requested fires for a Delta-enabled channel, the
outbound payload carries the full payment context in paymentDetails (paymentRequestId,
senderAddress, chainId, category, memo, executionMode, walletId, context,
metadata, and timestamps, in addition to the standard fields) plus invoice context from the
typed PaymentRequest invoice record when present, with a fallback to legacy context.invoice
data for older requests. It also includes the counterparty record and a pair of pre-minted
single-use action tokens so the pilot verification service can call back immediately. Abbreviated:
payment.executed, Conto sends an execution webhook
after the payment is submitted onchain, with the same invoice enrichment plus a transaction
block (transactionId, transactionHash, explorerUrl, executedAt), so the verifier can mark
its invoice row PAID without polling. Non-Delta WEBHOOK channels keep the standard payload
shape; this enrichment only appears for organizations that Conto has enabled for Delta. HMAC
signing is identical to the standard webhook channel
(X-Conto-Signature: sha256(${X-Conto-Timestamp}.${rawBody})).
2. Signed decision callback. For production verification services, prefer the signed callback
route to record the decision and (optionally) attach a proof reference:
actionToken.callbackUrl in the webhook payload remains the backwards-compatible demo path:
POST the approveToken or rejectToken to /api/approvals/action with the same optional
verification {} block. Both routes persist the same verification data, and proof material
surfaces on the Delta tab in the dashboard once your organization has Delta enabled.
Next Steps
Approval Workflows
Configure multi-approval workflows with escalation and sequential approvals
Securing Agents
Set up spending limits and approval thresholds for your agents