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

# Transaction events

> Follow a sponsored transaction from broadcast to its outcome

The `wallet.transaction.*` events report what happened to a transaction Dynamic sent on a user's behalf, including the ones that never land. Subscribe to them to tell a failed payment apart from one still in flight, without polling.

Available today for [gas-sponsored](/docs/embedded-wallets/gas-sponsorship) EVM transactions.

## The five events

| Event                             | Meaning                                                          | Final |
| --------------------------------- | ---------------------------------------------------------------- | ----- |
| `wallet.transaction.broadcasting` | Handed to the broadcaster. A transaction hash may not exist yet. | no    |
| `wallet.transaction.confirming`   | On the chain, waiting to be confirmed.                           | no    |
| `wallet.transaction.completed`    | Landed and confirmed.                                            | yes   |
| `wallet.transaction.reverted`     | Landed, and the contract rejected it.                            | yes   |
| `wallet.transaction.failed`       | Never landed and never will.                                     | yes   |

`reverted` and `failed` are separate because they call for different things. A revert means the transaction reached the chain and the contract refused it, so the call or the account state needs to change. A failure means it never got there at all.

## What to rely on

* **Exactly one final event per transaction.** `completed`, `reverted` and `failed` are mutually exclusive.
* **The others are best-effort.** A transaction that resolves quickly may skip `broadcasting` or `confirming`, so do not wait for them.
* **Order is not guaranteed.** Branch on the status in the payload, not on the order events arrive.
* **Delivery is at-least-once.** Deduplicate on the event id.
* **The transaction id is stable** across every event for one transaction, and matches the request id the sponsorship call returned.
* **Fields with nothing to report are left out** rather than sent as null, so check whether a field is present.

Each event carries the transaction id, its status, the wallet address, the chain, and when it was requested. Once the transaction reaches the chain it also carries the transaction hash and block explorer links, and a sponsored transaction carries the sponsoring address and the fees. The two failure events add a reason and a message.

For the shared event envelope and endpoint setup, see [Setting up webhooks](/docs/platform/dashboard/webhooks/setup).

## Failure reasons

The reason is a fixed code. The message beside it is human-readable, useful in a log or a support ticket, but not something to branch on.

| Reason                    | What happened                              | What to do                           |
| ------------------------- | ------------------------------------------ | ------------------------------------ |
| `CONTRACT_REVERTED`       | The contract rejected the call             | Fix the call or the account state    |
| `SPONSORSHIP_UNAVAILABLE` | Dynamic could not fund the transaction     | Retry, and contact us if it persists |
| `PROVIDER_ERROR`          | An upstream service failed                 | Retry                                |
| `INTERNAL_ERROR`          | A fault on our side                        | Retry, and contact us if it persists |
| `INVALID_REQUEST`         | The request was rejected before being sent | Correct the request                  |
| `UNKNOWN`                 | We could not classify it                   | Contact us                           |

A transaction rejected before reaching the chain arrives as `failed`, with the reason explaining why. So `failed` with `CONTRACT_REVERTED` means the call would have reverted and was never sent.

Treat the list as open. New codes can appear, so route anything unrecognised the same way you route `UNKNOWN`.

## Alongside on-chain activity

These events are independent of [`wallet.activity`](/docs/embedded-wallets/on-chain-events), and answer a different question.

|                     | `wallet.activity`                  | `wallet.transaction.*`           |
| ------------------- | ---------------------------------- | -------------------------------- |
| Answers             | Did funds move in this wallet?     | Did the transaction I sent land? |
| Covers              | Any sender, including deposits     | Only transactions Dynamic sent   |
| Moves no funds      | silent                             | still reports                    |
| Never lands         | silent                             | reports `failed`                 |
| Needs configuration | on-chain activity tracking enabled | gas sponsorship enabled          |

Where both are enabled and the wallet is registered for monitoring, a sponsored transfer that moves funds fires both, in no guaranteed order. Neither replaces the other, and neither guarantees the other will arrive.

If you already handle `wallet.activity` and only want to learn about failures, subscribe to `wallet.transaction.reverted` and `wallet.transaction.failed` alone.

## Getting started

1. [Set up a webhook endpoint](/docs/platform/dashboard/webhooks/setup)
2. Subscribe to the transaction events you want
3. Branch on the status, and deduplicate on the event id
