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
| State | Description | Final? |
|---|---|---|
quoted | Transaction created, awaiting confirmation | No |
userconfirmed | Confirmed by user, processing begins | No |
expired | Not confirmed or funded in time | Yes |
Source (Pay-In)
| State | Description | Final? |
|---|---|---|
srccreated | Source request created (invoice generated, address watching) | No |
srcsent | Deposit request sent to the network | No |
srcintent | Payment detected but unconfirmed (e.g., on-chain mempool) | No |
srcpendconfirmfill | Payment received, pending final confirmation | No |
srcconfirmfilled | Source payment fully confirmed | No |
Destination (Pay-Out)
| State | Description | Final? |
|---|---|---|
destpendsent | Payout queued, pending send | No |
destsent | Payout sent to destination | No |
Final States
| State | Description |
|---|---|
completed | Transaction fully settled -- both sides done |
expired | Timed out before confirmation or funding |
rejected | Rejected by the system (compliance, invalid destination) |
error | Non-recoverable error -- contact support |
usercanceled | Cancelled 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));
}
}Updated 6 days ago
