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

# Hooks Overview

> State recording system for tracking payment lifecycle events

## What are hooks

Hooks are pluggable contracts that update state **after** an action successfully executes on a PaymentOperator. Each operator has **5 hook slots**, one per action:

| Slot                         | Records after                          |
| ---------------------------- | -------------------------------------- |
| `AUTHORIZE_POST_ACTION_HOOK` | Authorization (for example, timestamp) |
| `CHARGE_POST_ACTION_HOOK`    | Charge event                           |
| `CAPTURE_POST_ACTION_HOOK`   | Capture from escrow                    |
| `VOID_POST_ACTION_HOOK`      | Void                                   |
| `REFUND_POST_ACTION_HOOK`    | Refund (after capture)                 |

These are the hook half of the operator's 10 slots. For the full slot layout alongside the pre-action conditions, see [PaymentOperator: 10-slot configuration](/contracts/payment-operator#10-slot-configuration).

## IHook Interface

```solidity theme={null}
interface IHook {
    function run(
        AuthCaptureEscrow.PaymentInfo calldata paymentInfo,
        uint256 amount,
        address caller,
        bytes calldata data
    ) external;
}
```

**Parameters:**

* `paymentInfo`, The payment information struct
* `amount`, The amount involved in the action
* `caller`, The address that executed the action (msg.sender on operator)
* `data`, Arbitrary data forwarded from the caller (signatures, proofs, attestations)

## Default behavior

**Hook slot = `address(0)`**: no-op (does nothing). The operator records no state for that slot.

Set hooks only on the slots where you want state tracking. Leave the rest as `address(0)`.

## BaseHook

All built-in hooks extend `BaseHook`, which verifies that the caller is an authorized operator. This prevents unauthorized contracts from writing state.

## Choosing a recording strategy

Not every payment needs on-chain hooks. Choose based on your use case:

### Events only (\~0 extra gas)

The operator already emits an event for every action (`AuthorizeExecuted`, `CaptureExecuted`, and the same shape for the rest). If you only need payment history for analytics or display, skip hooks entirely and index events off-chain.

**Best for:** micropayments, high-volume payments where gas overhead matters, simple UIs.

### Events plus subgraph (richest queries)

Index operator events with a subgraph for rich queries (payment history by payer, receiver, status, date range). No on-chain hook gas cost.

**Best for:** analytics dashboards, payment history, cross-payment queries.

**Trade-off:** requires subgraph infrastructure (semi-centralized).

### On-chain hooks (\~20k gas per write)

Use hooks when you need **on-chain reads**: other contracts or conditions that depend on recorded state. [EscrowPeriod](/contracts/conditions/escrow-period) is the most common example. It records authorization time so the capture condition can check if the escrow window has passed.

**Best for:** escrow enforcement, dispute evidence, decentralized frontends, on-chain composability.

**Trade-off:** \~20k gas per `SSTORE` operation.

### Decision table

| Need                    | Strategy          | Hook slots                                                                          |
| ----------------------- | ----------------- | ----------------------------------------------------------------------------------- |
| Payment history for UI  | Events only       | `address(0)`                                                                        |
| Rich queries, analytics | Events + Subgraph | `address(0)`                                                                        |
| Time-locked releases    | On-chain          | [EscrowPeriod](/contracts/conditions/escrow-period) on `AUTHORIZE_POST_ACTION_HOOK` |
| On-chain payment index  | On-chain          | [PaymentIndexRecorderHook](/contracts/hooks/payment-index)                          |
| Many data points        | On-chain          | [HookCombinator](/contracts/hooks/combinator)                                       |

<Tip>
  For most configurations, you only need a hook on the `AUTHORIZE_POST_ACTION_HOOK` slot (for [EscrowPeriod](/contracts/conditions/escrow-period)). Leave other hook slots as `address(0)`.
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="AuthorizationTimeRecorderHook" icon="clock" href="/contracts/hooks/authorization-time">
    Record authorization timestamps.
  </Card>

  <Card title="PaymentIndexRecorderHook" icon="list-ol" href="/contracts/hooks/payment-index">
    Index payments for on-chain queries.
  </Card>

  <Card title="HookCombinator" icon="layer-group" href="/contracts/hooks/combinator">
    Chain hooks into one slot.
  </Card>

  <Card title="Custom Hooks" icon="wrench" href="/contracts/hooks/custom">
    Build your own hook.
  </Card>
</CardGroup>
