Transaction Lifecycle

Every Neutron transaction follows a two-step flow: Create then Confirm. After confirmation, the transaction moves through states until it reaches a final state.

The Two-Step Flow

POST /api/v2/transaction/              -->  "quoted" (review fees and rate)
PUT  /api/v2/transaction/{id}/confirm  -->  processing begins

This design lets you show users the exact fees and exchange rate before committing.

Transaction States

Creation

StateDescriptionFinal?
quotedTransaction created, awaiting confirmationNo
userconfirmedConfirmed by user, processing beginsNo
expiredNot confirmed or funded in timeYes

Source (Pay-In)

StateDescriptionFinal?
srccreatedSource request created (invoice generated, address watching)No
srcsentDeposit request sent to the networkNo
srcintentPayment detected but unconfirmed (e.g., on-chain mempool)No
srcpendconfirmfillPayment received, pending final confirmationNo
srcconfirmfilledSource payment fully confirmedNo

Destination (Pay-Out)

StateDescriptionFinal?
destpendsentPayout queued, pending sendNo
destsentPayout sent to destinationNo

Final States

StateDescription
completedTransaction fully settled -- both sides done
expiredTimed out before confirmation or funding
rejectedRejected by the system (compliance, invalid destination)
errorNon-recoverable error -- contact support
usercanceledCancelled by user

Typical Flows by Method

Lightning (instant): quoted, userconfirmed, srccreated, srcconfirmfilled, completed

On-Chain Bitcoin: quoted, userconfirmed, srccreated, srcintent, srcpendconfirmfill, srcconfirmfilled, destsent, completed

Internal Swap: quoted, userconfirmed, completed

Fiat Payout: quoted, userconfirmed, srccreated, srcconfirmfilled, destpendsent, destsent, completed

Monitoring Transactions

Webhooks (recommended)

Register a webhook to receive automatic notifications on every state change.

Polling

Call GET /api/v2/transaction/{txnId} periodically:

const FINAL_STATES = ['completed', 'failed', 'expired', 'rejected', 'error', 'usercanceled'];

async function waitForCompletion(txnId, token) {
  while (true) {
    const res = await fetch(
      `https://api.neutron.me/api/v2/transaction/${txnId}`,
      { headers: { 'Authorization': `Bearer ${token}` } }
    );
    const txn = await res.json();
    if (FINAL_STATES.includes(txn.txnState)) return txn;
    await new Promise(r => setTimeout(r, 3000));
  }
}