Overview
The transaction status can be retrieved from the response of sendSignedTransaction, which waits for the transaction to be finalized and returns the complete transaction outcome.
The NEAR API TypeScript library automatically waits for transaction finalization when using sendSignedTransaction. The transaction status is included in the response.
Transaction Status Response
When you send a signed transaction, the response includes comprehensive status information:
const result = await client.sendSignedTransaction({
signedTransaction: signedTx,
});
if (result.ok) {
const status = result.value.rawRpcResult.status;
// Status will be one of: SuccessValue, SuccessReceiptId, or Failure
}
Source: packages/near-api-ts/universal/src/client/methods/transaction/sendSignedTransaction/handleResult/handleResult.ts:29-39
Status Types
Success Status
Transaction succeeded and returned a value (base64-encoded)if ('SuccessValue' in status) {
const returnValue = Buffer.from(status.SuccessValue, 'base64');
console.log('Return value:', returnValue.toString());
}
Transaction succeeded and generated a receiptif ('SuccessReceiptId' in status) {
console.log('Receipt ID:', status.SuccessReceiptId);
}
Failure Status
Transaction failed during executionDetails about which action failed and whyIndex of the action that failed
The specific error that occurred
if ('Failure' in status && 'ActionError' in status.Failure) {
const error = status.Failure.ActionError;
console.error(`Action ${error.index} failed:`, error.kind);
}
Transaction Outcome Details
The response includes detailed information about transaction execution:
Outcome of the transaction itselfAmount of gas burned during execution
Amount of tokens burned as fees (in yoctoNEAR)
Status of the transaction outcome
Log messages emitted during execution
IDs of receipts generated by this transaction
Array of outcomes for all receipts generated by the transactionEach receipt outcome contains:
id - Receipt ID
outcome - Execution outcome (gas, tokens, logs, status)
block_hash - Block where receipt was executed
Examples
Check Transaction Success
import { createClient, mainnet } from '@near-js/client';
const client = createClient({ network: mainnet });
const result = await client.sendSignedTransaction({
signedTransaction: signedTx,
});
if (!result.ok) {
console.error('Transaction failed to send:', result.error.kind);
process.exit(1);
}
const { rawRpcResult } = result.value;
const { status } = rawRpcResult;
// Check if transaction succeeded
if ('SuccessValue' in status || 'SuccessReceiptId' in status) {
console.log('✅ Transaction succeeded!');
console.log('Transaction hash:', rawRpcResult.transaction.hash);
} else if ('Failure' in status) {
console.error('❌ Transaction failed:', status.Failure);
}
const result = await client.sendSignedTransaction({
signedTransaction: signedTx,
});
if (result.ok) {
const { status } = result.value.rawRpcResult;
if ('SuccessValue' in status) {
// Decode base64 return value
const returnValueBytes = Buffer.from(status.SuccessValue, 'base64');
// Parse JSON if the contract returns JSON
try {
const returnValue = JSON.parse(returnValueBytes.toString());
console.log('Contract returned:', returnValue);
} catch {
console.log('Raw return value:', returnValueBytes.toString());
}
}
}
Analyze Gas Usage
const result = await client.sendSignedTransaction({
signedTransaction: signedTx,
});
if (result.ok) {
const { transaction_outcome, receipts_outcome } = result.value.rawRpcResult;
// Gas used by transaction
const txGas = BigInt(transaction_outcome.outcome.gas_burnt);
console.log('Transaction gas:', txGas.toString());
// Gas used by receipts
let totalReceiptGas = 0n;
for (const receipt of receipts_outcome) {
totalReceiptGas += BigInt(receipt.outcome.gas_burnt);
}
console.log('Receipt gas:', totalReceiptGas.toString());
// Total gas
const totalGas = txGas + totalReceiptGas;
console.log('Total gas burned:', totalGas.toString());
// Calculate cost in NEAR (1 TGas ≈ 0.0001 NEAR)
const gasCostNear = Number(totalGas) / 1e12 * 0.0001;
console.log('Approximate cost:', gasCostNear.toFixed(6), 'NEAR');
}
Handle Action Errors
const result = await client.sendSignedTransaction({
signedTransaction: signedTx,
});
if (result.ok) {
const { status } = result.value.rawRpcResult;
if ('Failure' in status && 'ActionError' in status.Failure) {
const actionError = status.Failure.ActionError;
console.error(`Action #${actionError.index} failed`);
// Handle specific error types
const { kind } = actionError;
if ('FunctionCallError' in kind) {
console.error('Function call failed:', kind.FunctionCallError);
} else if ('AccountAlreadyExists' in kind) {
console.error('Account already exists:', kind.AccountAlreadyExists);
} else if ('LackBalanceForState' in kind) {
console.error('Insufficient balance:', kind.LackBalanceForState);
} else {
console.error('Unknown error:', kind);
}
}
}
const result = await client.sendSignedTransaction({
signedTransaction: signedTx,
});
if (result.ok) {
const { transaction_outcome, receipts_outcome } = result.value.rawRpcResult;
// Logs from transaction
console.log('Transaction logs:', transaction_outcome.outcome.logs);
// Logs from receipts
for (const receipt of receipts_outcome) {
if (receipt.outcome.logs.length > 0) {
console.log(`Receipt ${receipt.id} logs:`, receipt.outcome.logs);
}
}
}
Track Cross-Contract Calls
const result = await client.sendSignedTransaction({
signedTransaction: signedTx,
});
if (result.ok) {
const { receipts_outcome } = result.value.rawRpcResult;
console.log(`Transaction generated ${receipts_outcome.length} receipts`);
for (const [index, receipt] of receipts_outcome.entries()) {
console.log(`\nReceipt #${index + 1}:`);
console.log(' ID:', receipt.id);
console.log(' Block:', receipt.block_hash);
console.log(' Gas burned:', receipt.outcome.gas_burnt);
console.log(' Status:', receipt.outcome.status);
if (receipt.outcome.logs.length > 0) {
console.log(' Logs:', receipt.outcome.logs);
}
}
}
Common Error Patterns
Function Call Errors
if ('Failure' in status) {
const failure = status.Failure;
if ('ActionError' in failure) {
const { kind } = failure.ActionError;
if ('FunctionCallError' in kind) {
const fnError = kind.FunctionCallError;
if ('ExecutionError' in fnError) {
console.error('Contract panic:', fnError.ExecutionError);
} else if ('MethodResolveError' in fnError) {
console.error('Method not found:', fnError.MethodResolveError);
}
}
}
}
Insufficient Balance
if ('Failure' in status && 'ActionError' in status.Failure) {
const { kind } = status.Failure.ActionError;
if ('LackBalanceForState' in kind) {
const { balance, amount } = kind.LackBalanceForState;
console.error(
`Insufficient balance: have ${balance}, need ${amount}`
);
}
}
Transaction Finality
The sendSignedTransaction method waits for FINAL status by default:
// Source: packages/near-api-ts/universal/src/client/methods/transaction/sendSignedTransaction/sendSignedTransaction.ts:43
wait_until: 'FINAL'
This means:
- Transaction is included in a block
- Block is finalized (irreversible)
- All receipts are executed
- Final status is known
Typically takes 2-3 seconds on NEAR.
Notes
- Transaction status is always available in
sendSignedTransaction response
- No separate “get status” API call is needed
- Status includes all receipt outcomes (cross-contract calls)
- Failed transactions still appear on-chain and consume gas
- Logs and return values are base64-encoded
- Gas amounts are in gas units (not NEAR)
- Token amounts are in yoctoNEAR (10^-24 NEAR)