Overview
The transactions API provides gas sponsorship for all wallet operations. The backend builds transaction bytes, sponsors gas, and co-signs transactions.
Wallet endpoints are public (no authentication). Status endpoint requires API key.
All wallet transactions follow a two-step flow:
Build : Wallet sends transaction parameters to /transactions/gas-sponsor
Submit : Wallet signs transaction bytes and submits via /transactions/submit
The backend acts as the gas sponsor, co-signing the transaction.
Endpoints
Build a gas-sponsored transaction and return transaction bytes for signing.
POST /api/identipay/v1/transactions/gas-sponsor
Request Body
Transaction type: send, settlement, settlement_no_zk, pool_deposit, or pool_withdraw
Additional Parameters by Type
Show send - Stealth Transfer
Specific coin object ID to spend (optional)
Recipient stealth address
Coin type (e.g., 0x2::sui::SUI)
Ephemeral public key (byte array)
View tag (0-255) for recipient filtering
Show settlement / settlement_no_zk - Pay Merchant
Specific coin object ID to spend (optional)
Coin type (e.g., 0x2::sui::SUI)
Buyer’s stealth address for this transaction
Intent signature (byte array)
Buyer’s public key (byte array)
Proposal expiry timestamp
Encrypted receipt payload (byte array)
Nonce for payload encryption (byte array)
Ephemeral pubkey for stealth announcement (byte array)
Encrypted warranty terms (byte array, optional)
Warranty nonce (byte array, optional)
Warranty expiry timestamp
Whether warranty is transferable
Stealth ephemeral pubkey (byte array, optional)
ZK proof for age gate (byte array, required for settlement, optional for settlement_no_zk)
ZK public inputs (byte array, required for settlement, optional for settlement_no_zk)
Show pool_deposit - Shielded Pool Deposit
Note commitment (byte array)
Show pool_withdraw - Shielded Pool Withdrawal
Change commitment (byte array)
ZK public inputs (byte array)
Response
Base64-encoded transaction bytes ready for signing
Example Request
cURL (Send)
TypeScript (Settlement)
curl -X POST https://api.identipay.com/api/identipay/v1/transactions/gas-sponsor \
-H "Content-Type: application/json" \
-d '{
"type": "send",
"senderAddress": "0xabc123...",
"amount": "1000000000",
"recipient": "0xdef456...",
"coinType": "0x2::sui::SUI",
"ephemeralPubkey": [1,2,3,...],
"viewTag": 42
}'
Example Response
{
"txBytes" : "AAACAAgA...(base64-encoded)..."
}
Error Responses
Show 400 Validation Error
Missing required parameters or invalid transaction type. {
"error" : {
"code" : "VALIDATION_ERROR" ,
"message" : "Missing required send parameters"
}
}
Failed to build transaction. {
"error" : {
"code" : "SUI_ERROR" ,
"message" : "Failed to build sponsored transaction" ,
"details" : { ... }
}
}
Submit Signed Transaction
Submit a signed transaction for co-signing and broadcasting.
POST /api/identipay/v1/transactions/submit
Request Body
Base64-encoded transaction bytes (from /gas-sponsor)
Base64-encoded sender signature
Response
Sui transaction digest (hash)
Example Request
curl -X POST https://api.identipay.com/api/identipay/v1/transactions/submit \
-H "Content-Type: application/json" \
-d '{
"txBytes": "AAACAAgA...",
"senderSignature": "ABC123..."
}'
Example Response
{
"txDigest" : "9x4Kb2FgH8..."
}
Error Responses
Show 400 Validation Error
Missing txBytes or senderSignature. {
"error" : {
"code" : "VALIDATION_ERROR" ,
"message" : "txBytes and senderSignature are required"
}
}
Failed to submit transaction. {
"error" : {
"code" : "SUI_ERROR" ,
"message" : "Failed to submit transaction" ,
"details" : { ... }
}
}
Submit Pool Transaction
Submit a pool withdrawal transaction (backend signs as both sender and gas sponsor).
POST /api/identipay/v1/transactions/submit-pool
Used for shielded pool withdrawals where the backend controls the pool account.
Request Body
Base64-encoded transaction bytes (from /gas-sponsor with type=pool_withdraw)
Response
Example Request
curl -X POST https://api.identipay.com/api/identipay/v1/transactions/submit-pool \
-H "Content-Type: application/json" \
-d '{
"txBytes": "AAACAAgA..."
}'
Example Response
{
"txDigest" : "7yZ3Jb1Hf9..."
}
Get Transaction Status
Check the status of a proposal/transaction (merchant endpoint).
GET /api/identipay/v1/transactions/:txId/status
Requires Authorization: Bearer {apiKey} header
Path Parameters
Response
Status: pending, settled, expired, or cancelled
Sui transaction digest (if settled)
ISO 8601 timestamp when settled (if settled)
Example Request
curl https://api.identipay.com/api/identipay/v1/transactions/550e8400-.../status \
-H "Authorization: Bearer ip_live_abc123..."
Example Response
{
"transactionId" : "550e8400-e29b-41d4-a716-446655440000" ,
"status" : "settled" ,
"suiTxDigest" : "9x4Kb2FgH8..." ,
"settledAt" : "2026-03-09T20:15:32.000Z"
}
Error Responses
Missing or invalid API key. {
"error" : {
"code" : "UNAUTHORIZED" ,
"message" : "Invalid API key"
}
}
Transaction not found or not owned by this merchant. {
"error" : {
"code" : "NOT_FOUND" ,
"message" : "Transaction not found"
}
}
Implementation Details
The backend uses Sui’s sponsored transaction feature:
Build Phase : Backend constructs a TransactionBlock with itself as the gas sponsor
Sign Phase : Wallet signs as the sender
Co-Sign Phase : Backend signs as the gas sponsor and submits
This allows users to transact without holding SUI for gas.
Security Model
The backend:
Only sponsors valid transaction types (whitelist)
Validates all transaction parameters
Never accesses user funds (users control their own keys)
Only pays gas fees
Settlement Flow
For a complete payment settlement:
Fetch Proposal : Wallet calls /intents/:txId
Verify Intent : Wallet validates merchant signature and intent hash
Generate Stealth Address : Wallet creates buyer stealth address
Build Settlement : Call /transactions/gas-sponsor with type=settlement
Sign Transaction : Wallet signs with user’s key
Submit : Call /transactions/submit
Monitor : Connect to WebSocket for real-time updates
See WebSocket for monitoring settlement status.
Background Settlement Indexer
The backend polls for SettlementEvent events every 3 seconds:
async function pollSettlementEvents () {
const result = await suiService . pollSettlementEvents ( cursor );
for ( const event of result . events ) {
const [ proposal ] = await db
. select ()
. from ( proposals )
. where ( eq ( proposals . intentHash , event . intentHash ));
if ( proposal && proposal . status === "pending" ) {
await db
. update ( proposals )
. set ({ status: "settled" , suiTxDigest: event . txDigest });
pushSettlementUpdate ( proposal . transactionId , "settled" , event . txDigest );
}
}
}
When a settlement is detected:
Update proposal status to settled
Store Sui transaction digest
Push update to all connected WebSocket clients