> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dakota.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Agentic Webhooks

> Failed payments emit the new scheduled_payment.failed; successful ones emit the standard wallet.transaction.created

Agentic payments adds exactly **one** webhook event: `scheduled_payment.failed`. Everything else rides signals you already consume.

For delivery mechanics — Ed25519 signature verification, targets, retries — see the main [Webhook Integration](/documentation/webhooks) guide. This page covers the agentic-specific payloads and how to react to them.

## Why only failures get a new event

A scheduled payment is the only *asynchronous* agentic actor: the platform fires it later, unattended. Every other agentic operation is synchronous — the caller holds the response.

* A scheduled payment that **succeeds** emits the standard **`wallet.transaction.created`** through the shared money path, indistinguishable from any other send. Correlate it via `wallet_transaction_id` on the executed scheduled payment (`GET /scheduled-payments`).
* A scheduled payment that **fails** emits **`scheduled_payment.failed`** with a machine-readable `failure_code`.

## `scheduled_payment.failed`

Fires on **every** fire-path failure: mandate denial, no covering mandate, agent revoked, wallet no longer recognizing the signer, chain-family mismatch, unsupported network, invalid amount, and money-path send errors. It does not fire for successful payments or for rows already in a terminal state.

### Payload (`data.object`)

| Field                  | Always present  | Notes                                                                            |
| ---------------------- | --------------- | -------------------------------------------------------------------------------- |
| `scheduled_payment_id` | ✅               | the failed schedule row                                                          |
| `signer_id`            | ✅               | the signer the row fires under                                                   |
| `wallet_id`            | ✅               | the funding wallet                                                               |
| `address`              | ✅               | the crypto address the row pays (for auto-account payments, the deposit address) |
| `amount`               | ✅               | decimal string, destination asset                                                |
| `asset`                | ✅               | e.g. `USDC`                                                                      |
| `network_id`           | ✅               | e.g. `base-sepolia`                                                              |
| `scheduled_at`         | ✅               | unix seconds                                                                     |
| `failure_code`         | ✅               | stable machine-readable code — **react on this**                                 |
| `failure_reason`       | ✅               | human-readable detail; wording may change, never parse it                        |
| `payment_agent_id`     | when applicable | the payment agent whose signer this is; omitted for non-agent signers            |
| `recipient_id`         | when applicable | present when the schedule targets a recipient's destination                      |
| `destination_id`       | when applicable | the real destination — bank for an offramp, crypto otherwise                     |

Optional fields are **omitted** when not applicable — treat absence as "not applicable", never as an empty string.

### `failure_code` reference

| Code                     | Meaning                                                                                       | Typical reaction                                          |
| ------------------------ | --------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| `mandate_denied`         | the mandate gate denied it — cap exhausted, target/asset/network mismatch, or validity window | adjust expectations or sign an additional mandate         |
| `no_mandate`             | no active mandate covered the payment at fire time                                            | create + approve a covering mandate                       |
| `agent_revoked`          | the payment agent was revoked                                                                 | expected if you revoked it; otherwise create a new agent  |
| `wallet_not_recognized`  | the signer is no longer recognized on the funding wallet                                      | re-attach the agent's signer to the wallet's signer group |
| `wallet_family_mismatch` | the wallet's chain family can't send on the payment's network                                 | schedule from a compatible wallet                         |
| `unsupported_network`    | the payment's network is not supported                                                        | fix the schedule                                          |
| `invalid_amount`         | the amount is unparseable or non-positive                                                     | fix the schedule                                          |
| `send_error`             | pre-checks passed but the send failed (provider/transport)                                    | often transient — re-schedule to retry                    |
| `internal_error`         | platform-side error during the fire                                                           | typically transient; retry or contact support             |

`failure_code` is the contract; `failure_reason` is diagnostic color for humans.

## Delivery & idempotency

The event is emitted **in the same transaction** as the payment's flip to `failed` — exactly one event exists per status change. Delivery, as with all Dakota webhooks, is at-least-once: **dedupe on the event `id`**.

Global webhook targets receive the event automatically; scoped targets subscribe to it by event type like any other. It also appears in the `GET /events` stream, so a poll-based consumer needs no webhook endpoint at all.

## A practical failure handler

```text theme={null}
on scheduled_payment.failed:
  if seen(event.id): ack and stop          # at-least-once delivery
  switch failure_code:
    case send_error, internal_error:       # transient
      re-schedule the payment (new POST /scheduled-payments)
    case no_mandate, mandate_denied:       # authority problem
      surface to the customer: review mandates, sign more headroom
    case wallet_not_recognized, wallet_family_mismatch, agent_revoked:
      surface to the operator: wiring problem, fix the binding
    default:                               # unsupported_network, invalid_amount
      fix the schedule data before retrying
```

The [Account Insights report](/documentation/agentic-payments/insights) also picks failures up (`payment_failures_clustered` groups repeats by payee and shared reason) — useful as the human-facing view over the same signal.
