Code & Invoice Transfers
Besides the instant Internal Transfer, TrexWallet supports code-based transfers: the sender (or recipient) creates a transfer code, hands it to the counterparty out of band, and the counterparty redeems it. There are four variants, formed by two orthogonal choices:
- Who initiates — the payer (funds-hold transfer) or the recipient (invoice).
- Confirmation — single-step, or a Safe variant that adds an explicit confirmation step (escrow-style).
typeTx | Name | Initiator | Funds locked at creation | Extra confirmation |
|---|---|---|---|---|
| 11 | InternalTx | payer | yes (creator) | no |
| 12 | InternalTxConfirm | payer | yes (creator) | yes — sender confirms after recipient joins |
| 13 | InvoiceTx | recipient | no | no |
| 14 | InvoiceTxConfirm | recipient | no | yes — payer confirms |
typeTx values match the public transaction-type enum 1:1. The transfer code identifies the
same transaction ID rather than creating a separate operation.
Endpoints
All three live under /trex/v1/ and use the authenticated session identity:
| Endpoint | Purpose |
|---|---|
POST /trex/v1/create_tx_code | Create a code/invoice, returns the encoded code. |
POST /trex/v1/apply_code | Redeem a code by code or id (transact timetick). |
POST /trex/v1/cancel_code | Cancel a pending code by code or id. |
apply_code and cancel_code accept either code (the bearer string) or id (the timetick) — passing both is rejected. Side/ownership checks are enforced per state, so id-based access carries the same security as code-based access.
1. Create the code
POST /trex/v1/create_tx_code
Content-Type: application/json
Cookie: sid=...
{
"amount": 100.0,
"currency": "USDT",
"typeTx": 12,
"timeLimit": false,
"partnerInfo": "Order #4821",
"tag": "deal with @bob"
}
The response (TxCodesOut) carries the encoded code, the timetick, and the current stateCode:
{
"timetick": 738291648372910,
"code": "B73UQPJN5Y6UP",
"currency": "USDT",
"amount": 100.0,
"typeTx": 12,
"stateCode": 1,
"state": "FundsHolded",
"isOwner": true,
"dateTxUTC": "2026-06-10T08:00:00Z"
}
What the server does at creation:
- Validates
amount > 0,partnerInfo/tag≤ 100 chars, currency exists. - Rejects if the wallet has
WalletBlock,InnerTransferBlock, orDeletedflags. - Resolves the
InnerTransfer-class tariff for the chosentypeTx. - Funds-hold types (11, 12): checks
free_balance ≥ amount, then locks the creator's funds —free_balance -= amount,lock_out_balance += amount(actionSFromFree | DFromOut). State becomesCreated/FundsHolded. - Invoice types (13, 14): no balance check and no money moves — the invoice is just a payment request. State becomes
Created/InvoiceCreated.
Set timeLimit: true to embed the creation timestamp in the code (enables time restrictions; makes the code string longer).
2. Redeem the code (apply_code)
POST /trex/v1/apply_code?code=B73UQPJN5Y6UP&amount=100.0&client_nonce=1739123
Behaviour depends on typeTx:
InternalTx (11) — funds-hold, single step
The redeemer is bound as the recipient (wallet_to) and the held funds settle immediately:
Created (FundsHolded)
└── recipient applies → Finished
creator.lock_out -= amount
recipient.free += amount - fee
Rejected with SameAccounts (10008) if the creator tries to redeem their own code.
InternalTxConfirm (12) — funds-hold + sender confirmation (escrow)
Two-stage. The recipient joins first; then the sender confirms to release the funds:
Created (FundsHolded)
└── recipient applies → Created|Confirmed (NeedConfirm) [recipient is now bound]
├── sender applies again → Finished [funds released to recipient]
└── cancel — see below
InvoiceTx (13) — invoice, single step
The redeemer is bound as the payer (wallet_from). The amount query parameter must equal the invoice amount, otherwise InvalidAmount (returned before any money moves):
Created (InvoiceCreated)
└── payer applies (amount must match) → Finished
payer.free -= amount
recipient.free += amount - fee
Rejected with SameAccounts if the invoice creator tries to pay their own invoice.
InvoiceTxConfirm (14) — invoice + payer confirmation
Two-stage on the payer side. First call binds the payer and locks funds; the response is NeedCodeConfirm. The second call (same payer, amount matching) finalizes:
Created (InvoiceCreated)
└── payer applies → Confirmed (NeedConfirm) → response: NeedCodeConfirm
└── payer applies again (amount must match) → Finished
Response (ApplyCodeOut)
| Field | Meaning |
|---|---|
confirmationStatusCode | Confirmed when settled; NeedCodeConfirm when a further confirmation step is required. |
txId | The transact timetick (string). |
result | Success / status text; for room-join codes holds the room timetick. |
Pass client_nonce for idempotency (see Error Handling); a repeated nonce is rejected with NonceExists (10130).
3. Cancel the code (cancel_code)
Who is allowed to cancel depends on the state — this is what makes the Confirm variants safe.
Funds-hold (InternalTx / InternalTxConfirm):
| State | Who may cancel | Effect |
|---|---|---|
Created (not yet redeemed) | creator (sender) only | Canceled — held funds returned to sender's free_balance |
Created|Confirmed (recipient joined) | recipient only | Canceled — funds returned to sender |
Invoice (InvoiceTx / InvoiceTxConfirm):
| State | Who may cancel | Effect |
|---|---|---|
Created (no payer yet) | creator (recipient) only | Canceled |
Created|Confirmed (payer joined) | payer | steps back to Predicted (payer detaches) |
Created|Confirmed (payer joined) | creator (recipient) | Canceled |
Escrow protection (safe deal)
The InternalTxConfirm flow is the escrow primitive. The key invariant:
Once the recipient (seller) has joined, the sender (buyer) can no longer cancel — only the seller can.
This blocks the fraud scenario where a buyer receives goods and then cancels the payment, keeping both the money and the goods. The buyer's funds stay locked in lock_out_balance until either the buyer confirms (funds go to the seller) or the seller voluntarily cancels (funds return to the buyer).
| State | Can finalize | Can cancel |
|---|---|---|
Created (before seller joins) | — | buyer (creator) |
Created|Confirmed (seller joined) | buyer | seller |
Code states (CodeStateEnum)
stateCode in TxCodesOut / TxCodeInfoOut converts the transaction state into a
client-friendly value:
stateCode | Name | Meaning |
|---|---|---|
| 0 | Unknown | Unrecognized state |
| 1 | FundsHolded | Funds locked, code waiting to be redeemed |
| 2 | InvoiceCreated | Invoice issued, awaiting a payer |
| 3 | NeedConfirm | Counterparty joined, confirmation required |
| 4 | NeedCancel | Cancellation in progress |
| 7 | Finished | Settled |
| 8 | Cancelled | Cancelled |
Related
- Internal Transfer — instant, no funds hold
- Sub-balances — how
free/lock_outbalances work - Fees
- Transaction States
- Error Handling