rtClient.pendingTransactions
SDK methods for registering and polling broadcast transactions whose confirmation is reconciled against the chain.
Substrate records (instances, payments, status flips) are created confirmed straight from the chainhook. If a chainhook is missed or delayed, that confirmation never lands and there is no server-side trace of the expected transaction. The pendingTransactions surface closes that gap: register a broadcast transaction id and a reconciler cron re-reads the chain and replays any stuck confirmation through the same idempotent handler.
When to call it:
- Bring-your-own-wallet flows call
registerright after broadcasting, then pollgetStatusto drive settling UX. - Privy flows self-register server-side at broadcast time - they only need to poll
getStatus.
See How State Syncs for what the protocol guarantees between broadcast and confirmation.
Register
rtClient.pendingTransactions.register(input)
Records that a broadcast transaction is expected to produce a chainhook event. Idempotent on txId - a repeat call returns the existing row.
const { data } = await rtClient.pendingTransactions.register({
txId: "0xabc...", // required - the broadcast transaction id
network: "testnet", // optional - "mainnet" | "testnet"
sourceApp: "grammata", // optional - cosmetic label for operator debugging
context: { kind: "edition" }, // optional - free-form, never branched on
});RegisterPendingTransactionInput:
| Field | Type | Required | Notes |
|---|---|---|---|
txId | string | yes | Broadcast transaction id. The only required field. |
network | "mainnet" | "testnet" | no | Defaults to the server's configured network. |
sourceApp | string | no | Client/operator label. Never affects reconciliation. |
contractAddress / contractName | string | no | The target contract. Passing both lets the server resolve the row's chainhookUuid at registration; omit and it resolves lazily on recovery. |
context | Record<string, unknown> | no | Free-form context, e.g. { kind: "edition" }. |
Status
rtClient.pendingTransactions.getStatus(txId)
Reads the current reconciliation status for a transaction. Poll this to drive a settling indicator; stop when status is CONFIRMED or FAILED. See Status Machines for every transition.
const { data } = await rtClient.pendingTransactions.getStatus("0xabc...");
if (data.status === "CONFIRMED") {
// confirmation landed - the chainhook applied its effects
}PendingTransactionStatus:
| Field | Type | Notes |
|---|---|---|
txId | string | The transaction id. |
status | PendingTxStatus | See lifecycle below. |
blockHeight | number | null | Set once the transaction is mined. |
resolvedAt | string | null | ISO timestamp when the row reached a terminal state. |
lastError | string | null | Populated on a failure terminal. |
Status lifecycle
PendingTxStatus:
| Value | Meaning | Terminal? |
|---|---|---|
BROADCAST | Registered, awaiting confirmation | No |
REPLAYING | The reconciler is replaying a missed confirmation | No |
CONFIRMED | The chainhook (or a replay) applied the transaction's effects | Yes |
FAILED | The transaction aborted on chain | Yes |
DROPPED | Never mined within the mempool window, or recovery exhausted | No - an operator can reopen it |
HANDLER_FAILED | The chainhook arrived but the handler threw - owned by the dead-letter queue, which can still confirm it | No |
The happy path is BROADCAST -> CONFIRMED; recovery from a missed chainhook is BROADCAST -> REPLAYING -> CONFIRMED. "Mined" is not a status - it is recorded as the blockHeight column, because a mined transaction can still be reversed by a reorg before it confirms.
Operator surface
Operators reconcile and browse pending transactions through RisingTideAdmin.pendingTransactions (list, reconcile). See Admin.