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

# waitForTransaction

> Polls a Starknet transaction to a terminal state and reports success, revert reason and raw events. A revert is a result, not an exception.

Every gasless write returns a transaction hash and nothing else. `waitForTransaction`
answers the two questions that follow: did it actually succeed, and what did it emit.

It is a standalone export, not a method on the SDK instance, so it needs no
`bearerToken`.

## Usage

```typescript theme={null}
import { waitForTransaction } from "@chipi-stack/backend";

const txHash = await sdk.callAnyContract({ params, bearerToken });
const receipt = await waitForTransaction(txHash);

if (!receipt.success) {
  throw new Error(receipt.revertReason ?? "reverted on chain");
}

const created = receipt.events.find(
  (e) => e.from_address === FACTORY && e.keys[0] === POOL_CREATED_SELECTOR
);
```

## Why a revert does not throw

<Warning>
  A **reverted** transaction comes back as a result (`success: false`), never as a thrown
  error. Only "we do not know yet" throws, meaning a timeout or a transport failure.
</Warning>

That split is deliberate, because these are the two ways a hand-rolled polling loop goes
wrong in a money flow:

* A revert read as success **double-credits a ledger**. So a revert is a normal outcome
  you must branch on, which makes it a return value.
* A timeout read as failure **strands a transfer that later confirms**. So a timeout is
  the one case where retrying is correct, which makes it an exception.

## Parameters

| Parameter                 | Type     | Required | Description                                          |
| ------------------------- | -------- | -------- | ---------------------------------------------------- |
| `transactionHash`         | `string` | Yes      | The hash returned by any write                       |
| `options.nodeUrl`         | `string` | No       | Preferred RPC endpoint, not the only one tried       |
| `options.retryIntervalMs` | `number` | No       | Poll interval. Default `3000`, roughly block cadence |
| `options.timeoutMs`       | `number` | No       | Total budget. Default `300000` (5 minutes)           |

Reading a receipt is idempotent, so `nodeUrl` is your slot in the ordered RPC chain: a
transport failure advances to the next endpoint instead of aborting the wait. It defaults
to the endpoint the SDK already uses for CHIPI wallets.

## Return value

Returns a `Promise<WaitForTransactionResult>`:

| Field             | Type                  | Description                                         |
| ----------------- | --------------------- | --------------------------------------------------- |
| `transactionHash` | `string`              | Echoed back                                         |
| `success`         | `boolean`             | True only for an accepted, non-reverted transaction |
| `executionStatus` | `string \| undefined` | Raw `execution_status` from the node                |
| `finalityStatus`  | `string \| undefined` | Raw `finality_status` from the node                 |
| `revertReason`    | `string \| undefined` | Present when `success` is false                     |
| `events`          | `ContractEventLog[]`  | Raw events. Empty on a revert                       |
| `blockNumber`     | `number \| undefined` | Block the transaction landed in                     |

Each event is `{ from_address, keys, data }`, exactly as the node returns it, for you to
decode against your own ABI. `keys[0]` is the selector of the event name, so filter on
`from_address` first, then match the selector.

## Pairing with treasury webhooks

`treasury.proposal.executed` carries `executedTxHash` but no receipt, by design. This is
the other half: take the hash from the webhook, resolve the receipt here, and read the
event you care about.

<Note>
  `RECEIVED`, `PENDING` and `PRE_CONFIRMED` all count as not-yet-final. A hash that has
  not propagated yet reads as an error on most nodes, which is treated as a normal early
  poll rather than a failure.
</Note>
