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

# Transaction

> The Transaction handle returned by sinker.enqueue(). Provides async access to status, lifecycle, and finalization.

## Overview

`sinker.enqueue()` returns a `Transaction` handle — a lightweight object tied to a specific `tx_id`. Use it to wait for confirmation, inspect status, or retrieve lifecycle history without managing raw HTTP calls.

```ts theme={null}
const handle = await sinker.enqueue(rawTxBase64);

// Wait for on-chain confirmation
const result = await handle.waitFor('finalized');
```

***

## Properties

<ResponseField name="txId" type="string">
  The `tx_id` assigned by the sidecar on enqueue. Use this to reference the
  transaction in other API calls.
</ResponseField>

<ResponseField name="enqueuedSlot" type="number">
  The slot at which the transaction was enqueued. Blockhashes are valid for 150 slots
  from their reference slot — monitor `age_slots` in the pending queue to detect
  near-expiry transactions.
</ResponseField>

***

## Methods

### handle.waitFor()

Wait until this transaction reaches the specified commitment state.

Subscribes to the per-transaction filtered SSE stream at `GET /tx/events/:tx_id`.
Resolves as soon as the target state (or any terminal state) is observed.

```ts theme={null}
const result = await handle.waitFor('finalized', timeoutMs?);
```

<ParamField path="state" type="TxState" required>
  The commitment level to wait for:

  * `'confirmed'` — supermajority vote. Fast (\~6–8s). Safe for most use cases.
  * `'finalized'` — irreversible. Slower (\~9–14s). Required for settlement finality.
</ParamField>

<ParamField path="timeoutMs" type="number" default="120000">
  Maximum wait time in milliseconds before the Promise rejects with a timeout error.
</ParamField>

**Returns:** `Promise<WaitResult>`

<ResponseField name="state" type="TxState">
  The actual state that triggered resolution (may be `'finalized'` even if you waited for `'confirmed'`).
</ResponseField>

<ResponseField name="bundle_id" type="string | null">
  The bundle ID that landed this transaction.
</ResponseField>

<ResponseField name="tx_signatures" type="string[]">
  On-chain signatures. Use these to look up the transaction on Solscan or the Jito explorer.
</ResponseField>

**Throws:**

* `Error` if the transaction reaches `'failed'` before the target state
* `Error` on timeout

**Example:**

```ts theme={null}
try {
  const { state, tx_signatures } = await handle.waitFor('finalized');
  console.log('Finalized:', tx_signatures[0]);
} catch (err) {
  if (err.message.includes('failed')) {
    console.log('Transaction failed — check handle.lifecycle() for failure class');
  }
}
```

***

### handle.status()

Fetch the current status of this transaction from the sidecar.

Uses a 3-tier lookup: memory cache → lifecycle log → 404.

```ts theme={null}
const status = await handle.status();

console.log(status.state);          // 'confirmed'
console.log(status.bundle_id);      // 'b9e8b294...'
console.log(status.tx_signatures);  // ['3b9QQcUQ...']
console.log(status.failure);        // null (or 'fee_too_low')
console.log(status.explorer_links); // { solscan: [...], jito: '...' }
```

**Returns:** `Promise<TxStatus>`

***

### handle.lifecycle()

Fetch all lifecycle entries (bundle attempts) for this `tx_id`.

A transaction that was retried after a failure will appear in multiple entries — one per bundle attempt. Inspect the `failure` and `ai_decision_trace` fields to understand what happened.

```ts theme={null}
const entries = await handle.lifecycle();

for (const entry of entries) {
  console.log('Attempt:', entry.bundle_id);
  console.log('Stage:',   entry.stage);
  console.log('Failure:', entry.failure?.type ?? 'none');
  console.log('Agent reasoning:', entry.ai_decision_trace);
}
```

**Returns:** `Promise<LifecycleEntry[]>`

***

### handle.rawBytes()

Retrieve the retained base64 transaction bytes for manual retry or inspection.

Bytes are captured by the sidecar at submit time and stored in memory for the lifetime of the process. They're independent of the original signing infrastructure — no keypair needed.

```ts theme={null}
const bytes = await handle.rawBytes();
// bytes is the original base64 wire tx you passed to sinker.enqueue()
```

**Returns:** `Promise<string>`

<Note>
  `rawBytes()` returns `404` (as a `SinkerError`) if the transaction has never been submitted — i.e., it's still in the pending queue. Wait for at least one submit attempt before calling this.
</Note>
