> ## 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.

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.

## Calling it from the client

Supported. `waitForTransaction` reads a receipt over RPC and needs no secret, so
importing it into a browser hook is a first-class use, not a workaround.

> [!NOTE]
>
> This is now a guarantee rather than an accident. Until `14.12.1` the constants
> module read `process.env` at module scope, so a client import only worked
> because bundlers inject a `process.env` shim. Those reads are guarded, and a
> test fails the build if a bare `process.env` reappears in a browser-bundled
> module.

Anything needing a `sk_` stays server-only. That split is about the secret, not
about the runtime: `waitForTransaction` has no secret to leak.

## 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.