Examples
All examples use the public Caddy gateway URL. Replace placeholders before running paid retries.
MCP discovery tool
After connecting to https://canix402-mcp.compx.io/mcp, call canix_get_discovery for
the same endpoint catalog as HTTP /discovery (free tool).
# Example: MCP client invokes canix_get_discovery (no payment required)
# Paid tools: first call returns PAYMENT_REQUIRED; retry with paymentSignature Discovery fetch (HTTP)
curl -s https://canix402-api.compx.io/discovery | jq '.data.endpoints[] | {path, access, summary}' OpenAPI fetch
curl -s https://canix402-api.compx.io/openapi.json | jq '.info, (.paths | keys)' MCP paid tool retry shape
Paid MCP tools mirror the HTTP x402 flow. First invocation returns payment metadata; retry
passes the signed payload as paymentSignature (tool argument, not an HTTP header).
// 1) canix_list_opportunities({ limit: 10 })
// -> PAYMENT_REQUIRED + paymentRequiredHeader metadata
// 2) canix_list_opportunities({
// limit: 10,
// paymentSignature: "<base64-json-payload>"
// })
// -> opportunity data Signed retry shape (HTTP)
The website does not sign payments. Your agent/client wallet must build this payload.
{
"x402Version": 2,
"scheme": "exact",
"network": "algorand-mainnet",
"accepted": { /* selected accept option from PAYMENT-REQUIRED */ },
"payload": {
"paymentGroup": ["<base64-signed-txn>"],
"paymentIndex": 0
},
"paymentRequired": { /* decoded PAYMENT-REQUIRED */ }
} Sample response payloads
executionShapes, compatibleExitShapes, and
(for Réti) entryRequirements / capacity. Numeric values follow the
precision contract (6 decimal places by default, up to 12 for small non-zero values). Live
responses vary in values and row count; the shape and field semantics match. The full
machine-readable schema and examples are published in
OpenAPI.
Aggregated opportunities
GET /opportunities — top opportunities across all protocols, ranked by APY.
curl -i https://canix402-api.compx.io/opportunities Sample response (200)
{
"data": [
{
"protocol": "tinyman",
"opportunityType": "lp",
"opportunityId": "tinyman:pool:1002541853",
"assetPair": "ALGO/USDC",
"assetIds": [
0,
31566704
],
"apr": 10.512,
"apy": 12.5,
"yieldBasis": "apy",
"tvlUsd": 2450000.5,
"sourceTimestamp": "2026-07-06T09:00:00.000Z",
"fetchedAt": "2026-07-06T09:00:00.000Z",
"notes": "sourceTimestamp reflects fetch time; upstream does not expose a per-row update time.",
"executionReady": true,
"executionShapes": [
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:flexible",
"protocol": "tinyman",
"protocolVersion": "v2",
"action": "addLiquidity",
"variant": "flexible",
"title": "Tinyman v2 flexible add liquidity",
"summary": "Adds two-sided liquidity to an existing Tinyman AMM v2 pool using flexible amounts. Generates the documented 3-transaction group (asset1 transfer, asset2 transfer/payment, add_liquidity app call) as unsigned transactions.",
"order": 0,
"requiredInputs": [
"userAddress",
"assetAId",
"assetAAmount",
"assetBId",
"assetBAmount",
"maxSlippageBps"
],
"requiredAssetIds": [
0,
31566704
],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "tinyman:pool:1002541853"
}
},
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:initial",
"protocol": "tinyman",
"protocolVersion": "v2",
"action": "addLiquidity",
"variant": "initial",
"title": "Tinyman v2 initial add liquidity",
"summary": "Adds the first liquidity to a bootstrapped but empty Tinyman AMM v2 pool. Generates the documented 3-transaction group (asset1 transfer, asset2 transfer/payment, add_initial_liquidity app call) as unsigned transactions.",
"order": 0,
"requiredInputs": [
"userAddress",
"assetAId",
"assetAAmount",
"assetBId",
"assetBAmount",
"maxSlippageBps"
],
"requiredAssetIds": [
0,
31566704
],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "tinyman:pool:1002541853"
}
},
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:singleAsset",
"protocol": "tinyman",
"protocolVersion": "v2",
"action": "addLiquidity",
"variant": "singleAsset",
"title": "Tinyman v2 single-asset add liquidity",
"summary": "Adds one-sided liquidity to an existing Tinyman AMM v2 pool. Tinyman performs an internal swap to balance the deposit and mints pool tokens. Generates the documented 2-transaction group (asset transfer/payment, add_liquidity app call) as unsigned transactions.",
"order": 0,
"requiredInputs": [
"userAddress",
"assetAId",
"assetBId",
"depositAssetId",
"depositAmount",
"maxSlippageBps"
],
"requiredAssetIds": [
0,
31566704
],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "tinyman:pool:1002541853"
}
}
],
"compatibleExitShapes": []
},
{
"protocol": "compx",
"opportunityType": "lending",
"opportunityId": "compx-lending-3491050310",
"assetPair": "USDC",
"assetIds": [
31566704,
3491050538
],
"apy": 1.4,
"apr": 1.4,
"borrowApr": 8.5,
"yieldBasis": "apr",
"tvlUsd": 137.181191,
"sourceTimestamp": "2026-07-14T20:47:17.000Z",
"fetchedAt": "2026-07-17T12:41:14.931Z",
"notes": "CompX lending market 3491050310; util=4.4%; ltv=70.0%; APR-derived yields; borrowApr is the borrow cost.",
"executionReady": true,
"executionShapes": [
{
"shapeKey": "mainnet:compx:v1:deposit:asa",
"protocol": "compx",
"protocolVersion": "v1",
"action": "deposit",
"variant": "asa",
"title": "CompX v1 ASA lending deposit",
"summary": "Deposits a base ASA into a CompX lending market and receives LST tokens.",
"order": 0,
"requiredInputs": [
"userAddress",
"marketAppId",
"amount"
],
"requiredAssetIds": [
31566704
],
"inputHints": {
"assetId": 31566704,
"marketAppId": 3491050310
}
},
{
"shapeKey": "mainnet:compx:v1:borrow:asa",
"protocol": "compx",
"protocolVersion": "v1",
"action": "borrow",
"variant": "asa",
"title": "CompX v1 ASA lending borrow",
"summary": "Borrows a base ASA from a CompX lending market against LST collateral.",
"order": 0,
"requiredInputs": [
"userAddress",
"marketAppId",
"borrowAmount",
"collateralAmount"
],
"requiredAssetIds": [
31566704
],
"inputHints": {
"assetId": 31566704,
"marketAppId": 3491050310
}
}
],
"compatibleExitShapes": [
{
"shapeKey": "mainnet:compx:v1:withdraw:asa",
"protocol": "compx",
"protocolVersion": "v1",
"action": "withdraw",
"variant": "asa",
"title": "CompX v1 ASA lending withdraw",
"summary": "Withdraws a base ASA from a CompX lending market by redeeming LST tokens.",
"order": 0,
"requiredInputs": [
"userAddress",
"marketAppId",
"amount"
],
"requiredAssetIds": [
31566704
],
"inputHints": {
"assetId": 31566704,
"marketAppId": 3491050310
}
},
{
"shapeKey": "mainnet:compx:v1:repay:asa",
"protocol": "compx",
"protocolVersion": "v1",
"action": "repay",
"variant": "asa",
"title": "CompX v1 ASA lending repay",
"summary": "Repays outstanding base-ASA debt on a CompX lending market.",
"order": 0,
"requiredInputs": [
"userAddress",
"marketAppId",
"amount"
],
"requiredAssetIds": [
31566704
],
"inputHints": {
"assetId": 31566704,
"marketAppId": 3491050310
}
}
]
},
{
"protocol": "reti",
"opportunityType": "staking",
"opportunityId": "reti-staking-12",
"assetPair": "ALGO",
"assetIds": [
0
],
"apy": 8.5,
"apr": 8.5,
"yieldBasis": "apr",
"tvlUsd": 125000.5,
"sourceTimestamp": "2026-07-23T10:00:00.000Z",
"fetchedAt": "2026-07-23T10:00:00.000Z",
"entryRequirements": {
"minAmount": {
"assetId": 0,
"amount": "1000000000"
},
"eligibilityFullyCheckable": true
},
"capacity": {
"stakerSlotsRemaining": 20,
"algoRoomMicroAlgos": "50000000000",
"acceptingStake": true
},
"notes": "Réti validator-level consensus staking; quote-time eligibility checks are authoritative.",
"executionReady": true,
"executionShapes": [
{
"shapeKey": "mainnet:reti:v1:stake:algo",
"protocol": "reti",
"protocolVersion": "v1",
"action": "stake",
"variant": "algo",
"title": "Réti ALGO stake to validator",
"summary": "Stakes ALGO to a Réti validator via ValidatorRegistry.addStake. The registry allocates into one of the validator's pools. Builds gas ×2, ALGO payment to the registry, addStake, and optional reward-token opt-in. Enforces minEntryStake, capacity, and entry gates at quote time.",
"order": 0,
"requiredInputs": [
"userAddress",
"validatorId",
"amount"
],
"requiredAssetIds": [
0
],
"inputHints": {
"validatorId": 12,
"assetId": 0,
"depositAssetId": 0
}
}
],
"compatibleExitShapes": [
{
"shapeKey": "mainnet:reti:v1:unstake:algo",
"protocol": "reti",
"protocolVersion": "v1",
"action": "unstake",
"variant": "algo",
"title": "Réti ALGO unstake from pool",
"summary": "Removes ALGO stake from a Réti staking pool via StakingPool.removeStake. Builds gas ×2, removeStake, and optional reward-token opt-in. Partial unstake must leave at least minEntryStake (or unstake the full balance).",
"order": 0,
"requiredInputs": [
"userAddress",
"validatorId",
"poolAppId",
"amount"
],
"requiredAssetIds": [
0
],
"inputHints": {
"validatorId": 12,
"assetId": 0,
"depositAssetId": 0
}
}
]
},
{
"protocol": "folks-finance",
"opportunityType": "lending",
"opportunityId": "folks-lending-971254667",
"assetPair": "USDC",
"assetIds": [
31566704
],
"apy": 6.06,
"apr": 5.9,
"borrowApr": 8.25,
"yieldBasis": "apy",
"tvlUsd": 29846.609471,
"sourceTimestamp": "2026-07-06T08:55:00.000Z",
"fetchedAt": "2026-07-06T09:00:00.000Z",
"executionReady": true,
"executionShapes": [
{
"shapeKey": "mainnet:folks-finance:v2:setup:depositEscrow",
"protocol": "folks-finance",
"protocolVersion": "v2",
"action": "setup",
"variant": "depositEscrow",
"title": "Folks Finance v2 add deposit escrow",
"summary": "Creates and funds a new Folks Finance deposit escrow for the user. Returns a 3-transaction group that must be signed by both the user and the generated escrow account.",
"order": 0,
"requiredInputs": [
"userAddress"
],
"requiredAssetIds": [
31566704
],
"inputHints": {
"poolAppId": 971254667,
"assetId": 31566704
}
},
{
"shapeKey": "mainnet:folks-finance:v2:setup:optEscrowAsset",
"protocol": "folks-finance",
"protocolVersion": "v2",
"action": "setup",
"variant": "optEscrowAsset",
"title": "Folks Finance v2 opt deposit escrow into pool fAsset",
"summary": "Funds and opts an existing Folks Finance deposit escrow into a pool fAsset so it can receive deposits.",
"order": 1,
"prerequisiteShapeKeys": [
"mainnet:folks-finance:v2:setup:depositEscrow"
],
"requiredInputs": [
"userAddress",
"escrowAddress"
],
"requiredAssetIds": [
31566704
],
"inputHints": {
"poolAppId": 971254667,
"assetId": 31566704
}
},
{
"shapeKey": "mainnet:folks-finance:v2:deposit:escrow",
"protocol": "folks-finance",
"protocolVersion": "v2",
"action": "deposit",
"variant": "escrow",
"title": "Folks Finance v2 escrow deposit",
"summary": "Deposits an underlying asset into a Folks Finance lending pool via a deposit escrow. fAssets accrue in the escrow rather than the user's wallet. Generates the SDK deposit group (asset transfer + deposit app call), optionally prefixed with OpUp.",
"order": 2,
"prerequisiteShapeKeys": [
"mainnet:folks-finance:v2:setup:optEscrowAsset"
],
"requiredInputs": [
"userAddress",
"assetAmount"
],
"requiredAssetIds": [
31566704
],
"inputHints": {
"poolAppId": 971254667,
"assetId": 31566704
}
}
],
"compatibleExitShapes": []
}
],
"meta": {
"limit": 10,
"offset": 0,
"includeInactive": false,
"paymentRequired": true
}
} Filtered search
GET /opportunities/search — caller-filtered opportunities by platform, type, APY, and TVL.
curl -i 'https://canix402-api.compx.io/opportunities/search?platform=tinyman&minApy=0.05' Sample response (200)
{
"data": [
{
"protocol": "tinyman",
"opportunityType": "lp",
"opportunityId": "tinyman:pool:1002541853",
"assetPair": "ALGO/USDC",
"assetIds": [
0,
31566704
],
"apr": 10.512,
"apy": 12.5,
"yieldBasis": "apy",
"tvlUsd": 2450000.5,
"sourceTimestamp": "2026-07-06T09:00:00.000Z",
"fetchedAt": "2026-07-06T09:00:00.000Z",
"executionReady": true,
"executionShapes": [
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:flexible",
"protocol": "tinyman",
"protocolVersion": "v2",
"action": "addLiquidity",
"variant": "flexible",
"title": "Tinyman v2 flexible add liquidity",
"summary": "Adds two-sided liquidity to an existing Tinyman AMM v2 pool using flexible amounts. Generates the documented 3-transaction group (asset1 transfer, asset2 transfer/payment, add_liquidity app call) as unsigned transactions.",
"order": 0,
"requiredInputs": [
"userAddress",
"assetAId",
"assetAAmount",
"assetBId",
"assetBAmount",
"maxSlippageBps"
],
"requiredAssetIds": [
0,
31566704
],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "tinyman:pool:1002541853"
}
},
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:initial",
"protocol": "tinyman",
"protocolVersion": "v2",
"action": "addLiquidity",
"variant": "initial",
"title": "Tinyman v2 initial add liquidity",
"summary": "Adds the first liquidity to a bootstrapped but empty Tinyman AMM v2 pool. Generates the documented 3-transaction group (asset1 transfer, asset2 transfer/payment, add_initial_liquidity app call) as unsigned transactions.",
"order": 0,
"requiredInputs": [
"userAddress",
"assetAId",
"assetAAmount",
"assetBId",
"assetBAmount",
"maxSlippageBps"
],
"requiredAssetIds": [
0,
31566704
],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "tinyman:pool:1002541853"
}
},
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:singleAsset",
"protocol": "tinyman",
"protocolVersion": "v2",
"action": "addLiquidity",
"variant": "singleAsset",
"title": "Tinyman v2 single-asset add liquidity",
"summary": "Adds one-sided liquidity to an existing Tinyman AMM v2 pool. Tinyman performs an internal swap to balance the deposit and mints pool tokens. Generates the documented 2-transaction group (asset transfer/payment, add_liquidity app call) as unsigned transactions.",
"order": 0,
"requiredInputs": [
"userAddress",
"assetAId",
"assetBId",
"depositAssetId",
"depositAmount",
"maxSlippageBps"
],
"requiredAssetIds": [
0,
31566704
],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "tinyman:pool:1002541853"
}
}
],
"compatibleExitShapes": []
}
],
"meta": {
"limit": 25,
"offset": 0,
"includeInactive": false,
"paymentRequired": true
}
} Wallet-personalized opportunities
GET /opportunities/personalized — opportunities tuned to a wallet's held assets.
Matching applies POST /eligibility rules so full or gated venues are not
recommended as enterable. Rows include canEnter and
eligibilityFullyCheckable; meta.eligibilityEndpoint is
/eligibility.
curl -i 'https://canix402-api.compx.io/opportunities/personalized?address=YOUR_ALGORAND_ADDRESS' Sample response (200)
{
"data": [
{
"protocol": "folks-finance",
"opportunityType": "lending",
"opportunityId": "folks-lending-971365552",
"assetPair": "ALGO",
"assetIds": [
0
],
"apy": 4.25,
"yieldBasis": "apy",
"tvlUsd": 1875000.25,
"sourceTimestamp": "2026-07-06T08:55:00.000Z",
"fetchedAt": "2026-07-06T09:00:00.000Z",
"executionReady": true,
"executionShapes": [
{
"shapeKey": "mainnet:folks-finance:v2:setup:depositEscrow",
"protocol": "folks-finance",
"protocolVersion": "v2",
"action": "setup",
"variant": "depositEscrow",
"title": "Folks Finance v2 add deposit escrow",
"summary": "Creates and funds a new Folks Finance deposit escrow for the user. Returns a 3-transaction group that must be signed by both the user and the generated escrow account.",
"order": 0,
"requiredInputs": [
"userAddress"
],
"requiredAssetIds": [
0
],
"inputHints": {
"poolAppId": 971365552,
"assetId": 0
}
},
{
"shapeKey": "mainnet:folks-finance:v2:setup:optEscrowAsset",
"protocol": "folks-finance",
"protocolVersion": "v2",
"action": "setup",
"variant": "optEscrowAsset",
"title": "Folks Finance v2 opt deposit escrow into pool fAsset",
"summary": "Funds and opts an existing Folks Finance deposit escrow into a pool fAsset so it can receive deposits.",
"order": 1,
"prerequisiteShapeKeys": [
"mainnet:folks-finance:v2:setup:depositEscrow"
],
"requiredInputs": [
"userAddress",
"escrowAddress"
],
"requiredAssetIds": [
0
],
"inputHints": {
"poolAppId": 971365552,
"assetId": 0
}
},
{
"shapeKey": "mainnet:folks-finance:v2:deposit:escrow",
"protocol": "folks-finance",
"protocolVersion": "v2",
"action": "deposit",
"variant": "escrow",
"title": "Folks Finance v2 escrow deposit",
"summary": "Deposits an underlying asset into a Folks Finance lending pool via a deposit escrow. fAssets accrue in the escrow rather than the user's wallet. Generates the SDK deposit group (asset transfer + deposit app call), optionally prefixed with OpUp.",
"order": 2,
"prerequisiteShapeKeys": [
"mainnet:folks-finance:v2:setup:optEscrowAsset"
],
"requiredInputs": [
"userAddress",
"assetAmount"
],
"requiredAssetIds": [
0
],
"inputHints": {
"poolAppId": 971365552,
"assetId": 0
}
}
],
"compatibleExitShapes": [],
"canEnter": true,
"eligibilityFullyCheckable": true
},
{
"protocol": "tinyman",
"opportunityType": "lp",
"opportunityId": "tinyman:pool:1002541853",
"assetPair": "ALGO/USDC",
"assetIds": [
0,
31566704
],
"apr": 10.512,
"apy": 12.5,
"yieldBasis": "apy",
"tvlUsd": 2450000.5,
"sourceTimestamp": "2026-07-06T09:00:00.000Z",
"fetchedAt": "2026-07-06T09:00:00.000Z",
"executionReady": true,
"executionShapes": [
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:flexible",
"protocol": "tinyman",
"protocolVersion": "v2",
"action": "addLiquidity",
"variant": "flexible",
"title": "Tinyman v2 flexible add liquidity",
"summary": "Adds two-sided liquidity to an existing Tinyman AMM v2 pool using flexible amounts. Generates the documented 3-transaction group (asset1 transfer, asset2 transfer/payment, add_liquidity app call) as unsigned transactions.",
"order": 0,
"requiredInputs": [
"userAddress",
"assetAId",
"assetAAmount",
"assetBId",
"assetBAmount",
"maxSlippageBps"
],
"requiredAssetIds": [
0,
31566704
],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "tinyman:pool:1002541853"
}
},
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:initial",
"protocol": "tinyman",
"protocolVersion": "v2",
"action": "addLiquidity",
"variant": "initial",
"title": "Tinyman v2 initial add liquidity",
"summary": "Adds the first liquidity to a bootstrapped but empty Tinyman AMM v2 pool. Generates the documented 3-transaction group (asset1 transfer, asset2 transfer/payment, add_initial_liquidity app call) as unsigned transactions.",
"order": 0,
"requiredInputs": [
"userAddress",
"assetAId",
"assetAAmount",
"assetBId",
"assetBAmount",
"maxSlippageBps"
],
"requiredAssetIds": [
0,
31566704
],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "tinyman:pool:1002541853"
}
},
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:singleAsset",
"protocol": "tinyman",
"protocolVersion": "v2",
"action": "addLiquidity",
"variant": "singleAsset",
"title": "Tinyman v2 single-asset add liquidity",
"summary": "Adds one-sided liquidity to an existing Tinyman AMM v2 pool. Tinyman performs an internal swap to balance the deposit and mints pool tokens. Generates the documented 2-transaction group (asset transfer/payment, add_liquidity app call) as unsigned transactions.",
"order": 0,
"requiredInputs": [
"userAddress",
"assetAId",
"assetBId",
"depositAssetId",
"depositAmount",
"maxSlippageBps"
],
"requiredAssetIds": [
0,
31566704
],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "tinyman:pool:1002541853"
}
}
],
"compatibleExitShapes": [],
"canEnter": true,
"eligibilityFullyCheckable": true
},
{
"protocol": "reti",
"opportunityType": "staking",
"opportunityId": "reti-staking-12",
"assetPair": "ALGO",
"assetIds": [
0
],
"apy": 8.5,
"apr": 8.5,
"yieldBasis": "apr",
"tvlUsd": 125000.5,
"sourceTimestamp": "2026-07-23T10:00:00.000Z",
"fetchedAt": "2026-07-23T10:00:00.000Z",
"entryRequirements": {
"minAmount": {
"assetId": 0,
"amount": "1000000000"
},
"eligibilityFullyCheckable": true
},
"capacity": {
"stakerSlotsRemaining": 20,
"algoRoomMicroAlgos": "50000000000",
"acceptingStake": true
},
"notes": "Réti validator-level consensus staking; quote-time eligibility checks are authoritative.",
"executionReady": true,
"executionShapes": [
{
"shapeKey": "mainnet:reti:v1:stake:algo",
"protocol": "reti",
"protocolVersion": "v1",
"action": "stake",
"variant": "algo",
"title": "Réti ALGO stake to validator",
"summary": "Stakes ALGO to a Réti validator via ValidatorRegistry.addStake. The registry allocates into one of the validator's pools. Builds gas ×2, ALGO payment to the registry, addStake, and optional reward-token opt-in. Enforces minEntryStake, capacity, and entry gates at quote time.",
"order": 0,
"requiredInputs": [
"userAddress",
"validatorId",
"amount"
],
"requiredAssetIds": [
0
],
"inputHints": {
"validatorId": 12,
"assetId": 0,
"depositAssetId": 0
}
}
],
"compatibleExitShapes": [
{
"shapeKey": "mainnet:reti:v1:unstake:algo",
"protocol": "reti",
"protocolVersion": "v1",
"action": "unstake",
"variant": "algo",
"title": "Réti ALGO unstake from pool",
"summary": "Removes ALGO stake from a Réti staking pool via StakingPool.removeStake. Builds gas ×2, removeStake, and optional reward-token opt-in. Partial unstake must leave at least minEntryStake (or unstake the full balance).",
"order": 0,
"requiredInputs": [
"userAddress",
"validatorId",
"poolAppId",
"amount"
],
"requiredAssetIds": [
0
],
"inputHints": {
"validatorId": 12,
"assetId": 0,
"depositAssetId": 0
}
}
],
"canEnter": true,
"eligibilityFullyCheckable": true
}
],
"meta": {
"limit": 10,
"offset": 0,
"includeInactive": false,
"paymentRequired": true,
"address": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"heldAssetCount": 2,
"eligibilityApplied": true,
"eligibilityEndpoint": "/eligibility"
}
} Eligibility and capacity
POST /eligibility — check whether a wallet can enter selected opportunities
before quoting. Returns canEnter, missingAssets,
gates, capacity, and optional suggestedSwap.
NFD/creator gates stay unresolved (eligibilityFullyCheckable: false).
curl -i https://canix402-api.compx.io/eligibility -H 'content-type: application/json' -d '{"address":"YOUR_ALGORAND_ADDRESS","opportunityIds":["reti-staking-12"]}' Sample response (200)
{
"data": [
{
"opportunityId": "reti-staking-12",
"protocol": "reti",
"found": true,
"canEnter": true,
"eligibilityFullyCheckable": true,
"missingAssets": [],
"gates": [],
"capacity": {
"stakerSlotsRemaining": 20,
"algoRoomMicroAlgos": "50000000000",
"acceptingStake": true
},
"suggestedSwap": null,
"reasons": []
}
],
"meta": {
"address": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"fetchedAt": "2026-08-14T21:00:00.000Z",
"paymentRequired": true,
"quoteTimeAuthoritative": true
}
} Intent compiler (paid)
POST /plans — flagship compiler SKU (~0.25 USDC). State an allocation intent
(address, budget/asset, constraints). Returns ordered steps: eligibility, optional swap hints,
protocol setup chains, and enter quotes as independent unsigned groups (never merged).
Reuses quotes[] / order / prerequisiteShapeKeys.
Brownie and other agents should consume this route rather than forking a compiler.
Canix never signs or submits.
curl -i https://canix402-api.compx.io/plans -H 'content-type: application/json' -d '{"address":"YOUR_ALGORAND_ADDRESS","budget":{"assetId":0,"amount":"1000000"},"constraints":{"noNewBorrows":true,"executionReadyOnly":true},"opportunityIds":["reti-staking-12"]}' Sample response (200)
{
"data": {
"allocations": [
{
"opportunityId": "reti-staking-12",
"protocol": "reti",
"opportunityType": "staking",
"assetPair": "ALGO",
"apy": 8.5,
"allocatedAmount": "1000000",
"allocatedAssetId": 0,
"weightBps": 10000,
"eligibility": {
"opportunityId": "reti-staking-12",
"protocol": "reti",
"found": true,
"canEnter": true,
"eligibilityFullyCheckable": true,
"missingAssets": [],
"gates": [],
"capacity": {
"stakerSlotsRemaining": 20,
"algoRoomMicroAlgos": "50000000000",
"acceptingStake": true
},
"suggestedSwap": null,
"reasons": []
},
"executionShapes": [
{
"shapeKey": "mainnet:reti:v1:stake:algo",
"protocol": "reti",
"protocolVersion": "v1",
"action": "stake",
"variant": "algo",
"title": "Réti ALGO stake to validator",
"summary": "Stakes ALGO to a Réti validator.",
"order": 0,
"requiredInputs": [
"userAddress",
"validatorId",
"amount"
],
"requiredAssetIds": [
0
],
"inputHints": {
"validatorId": 12,
"assetId": 0,
"depositAssetId": 0
}
}
],
"steps": [
{
"kind": "eligibility",
"order": 0,
"compileStatus": "compiled",
"warnings": []
},
{
"kind": "enter",
"order": 1,
"compileStatus": "compiled",
"shapeKey": "mainnet:reti:v1:stake:algo",
"quoteRequest": {
"shapeKey": "mainnet:reti:v1:stake:algo",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"validatorId": 12,
"assetId": 0,
"depositAssetId": 0,
"amount": "1000000"
}
},
"quote": {
"shapeKey": "mainnet:reti:v1:stake:algo",
"shapeVersion": "1.0.0",
"identity": {
"network": "mainnet",
"protocol": "reti",
"protocolVersion": "v1",
"action": "stake",
"variant": "algo"
},
"createdAt": "2026-08-16T10:00:00.000Z",
"expiresAt": "2026-08-16T10:00:30.000Z",
"transactions": [
{
"type": "pay",
"sender": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"fee": "1000",
"groupPresent": true
}
],
"encodedTransactions": [
"<base64-unsigned-txn>"
],
"warnings": [],
"metadata": {}
},
"warnings": []
}
],
"quotes": [
{
"shapeKey": "mainnet:reti:v1:stake:algo",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"validatorId": 12,
"assetId": 0,
"depositAssetId": 0,
"amount": "1000000"
}
}
]
}
],
"blocked": [],
"expectedPositionDelta": {
"summary": "Enter 1000000 of asset 0 into reti-staking-12 (reti).",
"entries": [
{
"opportunityId": "reti-staking-12",
"protocol": "reti",
"assetId": 0,
"amount": "1000000",
"action": "enter"
}
]
},
"fees": {
"x402Usdc": "0.25",
"estimatedNetworkFeeMicroAlgos": "1000",
"estimatedNetworkFeeUsd": null
},
"expiresAt": "2026-08-16T10:00:30.000Z",
"warnings": []
},
"meta": {
"address": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"budget": {
"assetId": 0,
"amount": "1000000"
},
"fetchedAt": "2026-08-16T10:00:00.000Z",
"paymentRequired": true,
"executionSubmitted": false,
"quoteTimeAuthoritative": true,
"eligibilityEndpoint": "/eligibility"
}
} Protocol-specific opportunities
GET /protocols/{protocol}/opportunities — opportunities for a single
protocol. Substitute any supported protocol (e.g. tinyman, pact,
folks-finance, compx, dorkfi, myth-finance,
haystack, reti, alpha-arcade).
curl -i https://canix402-api.compx.io/protocols/reti/opportunities Sample response (200)
{
"data": [
{
"protocol": "reti",
"opportunityType": "staking",
"opportunityId": "reti-staking-12",
"assetPair": "ALGO",
"assetIds": [
0
],
"apy": 8.5,
"apr": 8.5,
"yieldBasis": "apr",
"tvlUsd": 125000.5,
"sourceTimestamp": "2026-07-23T10:00:00.000Z",
"fetchedAt": "2026-07-23T10:00:00.000Z",
"entryRequirements": {
"minAmount": {
"assetId": 0,
"amount": "1000000000"
},
"eligibilityFullyCheckable": true
},
"capacity": {
"stakerSlotsRemaining": 20,
"algoRoomMicroAlgos": "50000000000",
"acceptingStake": true
},
"notes": "Réti validator-level consensus staking; quote-time eligibility checks are authoritative.",
"executionReady": true,
"executionShapes": [
{
"shapeKey": "mainnet:reti:v1:stake:algo",
"protocol": "reti",
"protocolVersion": "v1",
"action": "stake",
"variant": "algo",
"title": "Réti ALGO stake to validator",
"summary": "Stakes ALGO to a Réti validator via ValidatorRegistry.addStake. The registry allocates into one of the validator's pools. Builds gas ×2, ALGO payment to the registry, addStake, and optional reward-token opt-in. Enforces minEntryStake, capacity, and entry gates at quote time.",
"order": 0,
"requiredInputs": [
"userAddress",
"validatorId",
"amount"
],
"requiredAssetIds": [
0
],
"inputHints": {
"validatorId": 12,
"assetId": 0,
"depositAssetId": 0
}
}
],
"compatibleExitShapes": [
{
"shapeKey": "mainnet:reti:v1:unstake:algo",
"protocol": "reti",
"protocolVersion": "v1",
"action": "unstake",
"variant": "algo",
"title": "Réti ALGO unstake from pool",
"summary": "Removes ALGO stake from a Réti staking pool via StakingPool.removeStake. Builds gas ×2, removeStake, and optional reward-token opt-in. Partial unstake must leave at least minEntryStake (or unstake the full balance).",
"order": 0,
"requiredInputs": [
"userAddress",
"validatorId",
"poolAppId",
"amount"
],
"requiredAssetIds": [
0
],
"inputHints": {
"validatorId": 12,
"assetId": 0,
"depositAssetId": 0
}
}
]
}
],
"meta": {
"limit": 25,
"offset": 0,
"includeInactive": false,
"paymentRequired": true
}
} Execution shape catalog (free)
GET /execution/shapes — live catalog of verified shape keys, required inputs, and
docs paths. Metadata only; does not compile quotes.
curl -s https://canix402-api.compx.io/execution/shapes | jq '.meta, (.data | length)' Sample response (200, trimmed)
{
"data": [
{
"shapeKey": "mainnet:compx:v1:borrow:asa",
"network": "mainnet",
"protocol": "compx",
"protocolVersion": "v1",
"action": "borrow",
"variant": "asa",
"shapeVersion": "1.0.1",
"title": "CompX v1 ASA lending borrow",
"description": "Borrows a base ASA from a CompX lending market against accepted LST collateral. Collateral must be in the market's on-chain accepted_collaterals set (often a cross-market LST).",
"summary": "Borrows a base ASA from a CompX lending market against accepted LST collateral.",
"opportunityRole": "enter",
"supportedOpportunityTypes": [
"lending"
],
"requiredInputs": [
"userAddress",
"marketAppId",
"borrowAmount",
"collateralAmount"
],
"sources": [
{
"kind": "sdk",
"description": "@compx/sdk buildBorrowTransactions"
}
],
"docsPath": "protocol/docs/execution-shapes/compx-borrow-asa.md"
},
{
"shapeKey": "mainnet:compx:v1:repay:asa",
"network": "mainnet",
"protocol": "compx",
"protocolVersion": "v1",
"action": "repay",
"variant": "asa",
"shapeVersion": "1.0.1",
"title": "CompX v1 ASA lending repay",
"description": "Repays outstanding base-ASA debt on a CompX lending market. App-call fees are floored to at least 2000 microAlgos after SDK simulation.",
"summary": "Repays outstanding base-ASA debt on a CompX lending market.",
"opportunityRole": "exit",
"supportedOpportunityTypes": [
"lending"
],
"requiredInputs": [
"userAddress",
"marketAppId",
"amount"
],
"sources": [
{
"kind": "sdk",
"description": "@compx/sdk buildRepayTransactions"
}
],
"docsPath": "protocol/docs/execution-shapes/compx-repay-asa.md"
}
],
"meta": {
"paymentRequired": false,
"shapeCount": 2,
"note": "Catalog metadata only. Compile unsigned groups via paid POST /execution/quotes. Full catalog is larger; this sample is trimmed to CompX borrow/repay."
}
} Execution quotes (paid)
POST /execution/quotes — batch { quotes: [{ shapeKey, input }, ...] }
(~0.1 USDC flat per request). Returns unsigned groups; Canix never signs or submits.
Preflight returns 402 with PAYMENT-REQUIRED; retry with
PAYMENT-SIGNATURE (same pattern as opportunities).
1) Preflight (expect 402)
curl -i https://canix402-api.compx.io/execution/quotes \
-H 'content-type: application/json' \
-d '{
"quotes": [{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:flexible",
"input": {
"userAddress": "YOUR_ALGORAND_ADDRESS",
"assetAId": 0,
"assetAAmount": "1000000",
"assetBId": 31566704,
"assetBAmount": "1000000",
"maxSlippageBps": 50
}
}]
}' 2) Paid retry (enter liquidity)
curl -i https://canix402-api.compx.io/execution/quotes \
-H 'content-type: application/json' \
-H 'PAYMENT-SIGNATURE: <base64-json-payload>' \
-d '{
"quotes": [{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:flexible",
"input": {
"userAddress": "YOUR_ALGORAND_ADDRESS",
"assetAId": 0,
"assetAAmount": "1000000",
"assetBId": 31566704,
"assetBAmount": "1000000",
"maxSlippageBps": 50
}
}]
}' 3) Exit from a position (use compatibleExitShapeKeys)
After GET /positions, pick a key from compatibleExitShapeKeys and
fill inputs from that row's inputHints (plus amounts you choose locally).
curl -i https://canix402-api.compx.io/execution/quotes \
-H 'content-type: application/json' \
-H 'PAYMENT-SIGNATURE: <base64-json-payload>' \
-d '{
"quotes": [{
"shapeKey": "mainnet:tinyman:v2:removeLiquidity:multipleAssetsOut",
"input": {
"userAddress": "YOUR_ALGORAND_ADDRESS",
"poolId": "1002541853",
"assetAId": 0,
"assetBId": 31566704,
"poolTokenAmount": "1250000",
"maxSlippageBps": 50
}
}]
}' Sample response (200)
{
"data": [
{
"shapeKey": "mainnet:tinyman:v2:addLiquidity:flexible",
"shapeVersion": "1.0.0",
"network": "mainnet",
"expiresAt": "2026-07-23T12:00:30.000Z",
"encodedTransactions": [
"<base64-unsigned-txn-0>",
"<base64-unsigned-txn-1>"
],
"transactions": [
{
"type": "axfer",
"sender": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"fee": "1000",
"groupPresent": true
}
],
"metadata": {
"poolAddress": "TINYPQOLADDRESSPLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAA"
},
"warnings": []
}
],
"meta": {
"paymentRequired": true,
"executionSubmitted": false,
"quoteCount": 1,
"note": "Unsigned groups only. Sign and submit locally; Canix never receives wallet keys."
},
"claimBatchRequestExample": {
"quotes": [
{
"shapeKey": "mainnet:haystack:v1:claim:rewards",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"
}
},
{
"shapeKey": "mainnet:compx:v1:claim:rewards",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ",
"poolAppId": 123456
}
},
{
"shapeKey": "mainnet:alpha-arcade:v1:claimRewards:usdc",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"
}
}
],
"note": "Pass claimAllQuotes from GET /positions/claimable. Each quotes[] item compiles to an independent unsigned group; groups are never merged. Flat ~0.10 USDC per request."
}
} Wallet positions (paid)
GET /positions?address= — normalized DeFi positions with
compatibleExitShapeKeys / compatibleManageShapeKeys
(~0.005 USDC). Use those keys with POST /execution/quotes to exit or manage.
1) Preflight (expect 402)
curl -i 'https://canix402-api.compx.io/positions?address=YOUR_ALGORAND_ADDRESS' 2) Paid retry
curl -i 'https://canix402-api.compx.io/positions?address=YOUR_ALGORAND_ADDRESS' \
-H 'PAYMENT-SIGNATURE: <base64-json-payload>' Sample response (200)
{
"data": [
{
"protocol": "tinyman",
"positionType": "lp",
"positionId": "tinyman:lp:1002541853",
"opportunityId": "tinyman:pool:1002541853",
"assetId": 1002541853,
"assetSymbol": "TMPOOL2",
"amountRaw": "1250000",
"amount": "1.250000",
"usdValue": 42.5,
"compatibleExitShapeKeys": [
"mainnet:tinyman:v2:removeLiquidity:multipleAssetsOut",
"mainnet:tinyman:v2:removeLiquidity:singleAssetOut"
],
"compatibleManageShapeKeys": [],
"inputHints": {
"assetAId": 0,
"assetBId": 31566704,
"poolId": "1002541853"
}
},
{
"protocol": "compx",
"positionType": "debt",
"positionId": "compx:debt:3491050310",
"opportunityId": "compx-lending-3491050310",
"assetId": 31566704,
"assetSymbol": "USDC",
"amountRaw": "250000",
"amount": "0.250000",
"usdValue": 0.25,
"healthFactor": 1.8,
"compatibleExitShapeKeys": [
"mainnet:compx:v1:repay:asa"
],
"compatibleManageShapeKeys": [],
"notes": "Locked collateral 500000 of asset 3491050311 (LST units).",
"inputHints": {
"marketAppId": 3491050310,
"assetId": 31566704
}
}
],
"protocols": [
{
"protocol": "tinyman",
"status": "ok",
"positionCount": 1,
"message": null
},
{
"protocol": "compx",
"status": "ok",
"positionCount": 1,
"message": null
}
],
"totals": {
"suppliedUsd": 42.5,
"borrowedUsd": 0.25,
"rewardsUsd": 0,
"netUsd": 42.25
},
"meta": {
"address": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"fetchedAt": "2026-08-05T12:00:00.000Z",
"paymentRequired": true
}
} Claim desk (paid)
GET /positions/claimable?address= — claimable rewards with USD value,
network-fee / worth-claiming hints, and claimAllQuotes ready for
POST /execution/quotes (~0.001 USDC list; compile stays ~0.10 USDC flat).
Groups are never merged. Agent loop: positions (optional) → claimable → quote → local sign.
1) Preflight (expect 402)
curl -i 'https://canix402-api.compx.io/positions/claimable?address=YOUR_ALGORAND_ADDRESS' 2) Paid retry
curl -i 'https://canix402-api.compx.io/positions/claimable?address=YOUR_ALGORAND_ADDRESS' \
-H 'PAYMENT-SIGNATURE: <base64-json-payload>' 3) Compile claim-all (use claimAllQuotes)
curl -i https://canix402-api.compx.io/execution/quotes \
-H 'content-type: application/json' \
-H 'PAYMENT-SIGNATURE: <base64-json-payload>' \
-d '{
"quotes": [
{
"shapeKey": "mainnet:haystack:v1:claim:rewards",
"input": { "userAddress": "YOUR_ALGORAND_ADDRESS" }
},
{
"shapeKey": "mainnet:compx:v1:claim:rewards",
"input": { "userAddress": "YOUR_ALGORAND_ADDRESS", "poolAppId": 123456 }
}
]
}' Sample response (200)
{
"data": [
{
"protocol": "haystack",
"positionId": "haystack:reward:3321763884:usdc",
"opportunityId": "haystack-staking-hay",
"positionType": "reward",
"assetId": 31566704,
"assetSymbol": "USDC",
"amountRaw": "1500000",
"amount": "1.500000",
"usdValue": 1.5,
"claimKey": "haystack:claim:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ",
"compatibleClaimShapeKeys": [
"mainnet:haystack:v1:claim:rewards"
],
"quote": {
"shapeKey": "mainnet:haystack:v1:claim:rewards",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"
}
},
"estimatedNetworkFeeMicroAlgos": "5000",
"estimatedNetworkFeeUsd": 0.001,
"worthClaiming": true,
"caveats": [
"Pending USDC from staker box; live accrual may be higher until the next drip/claim."
]
},
{
"protocol": "haystack",
"positionId": "haystack:reward:3321763884:hay",
"opportunityId": "haystack-staking-hay",
"positionType": "reward",
"assetId": 3160000000,
"assetSymbol": "HAY",
"amountRaw": "25000000",
"amount": "25.000000",
"usdValue": 0.5,
"claimKey": "haystack:claim:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ",
"compatibleClaimShapeKeys": [
"mainnet:haystack:v1:claim:rewards"
],
"quote": {
"shapeKey": "mainnet:haystack:v1:claim:rewards",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"
}
},
"estimatedNetworkFeeMicroAlgos": "5000",
"estimatedNetworkFeeUsd": 0.001,
"worthClaiming": true
},
{
"protocol": "compx",
"positionId": "compx:reward:123456:31566704",
"opportunityId": "compx-staking-123456",
"positionType": "reward",
"assetId": 31566704,
"assetSymbol": "USDC",
"amountRaw": "500000",
"amount": "0.500000",
"usdValue": 0.5,
"claimKey": "compx:claim:123456",
"compatibleClaimShapeKeys": [
"mainnet:compx:v1:claim:rewards"
],
"quote": {
"shapeKey": "mainnet:compx:v1:claim:rewards",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ",
"poolAppId": 123456
}
},
"estimatedNetworkFeeMicroAlgos": "250000",
"estimatedNetworkFeeUsd": 0.05,
"worthClaiming": true,
"inputHints": {
"poolAppId": 123456,
"assetId": 31566704
}
},
{
"protocol": "tinyman",
"positionId": "tinyman:staked:stalgo:dummy",
"opportunityId": "tinyman-staking-stalgo",
"positionType": "staked",
"assetId": 0,
"assetSymbol": "stALGO",
"amountRaw": "1000000",
"amount": "1.000000",
"usdValue": null,
"claimKey": "tinyman:stalgo-claim:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ",
"compatibleClaimShapeKeys": [
"mainnet:tinyman:restake-v1:claimRewards:stAlgo"
],
"quote": {
"shapeKey": "mainnet:tinyman:restake-v1:claimRewards:stAlgo",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"
}
},
"estimatedNetworkFeeMicroAlgos": "2000",
"estimatedNetworkFeeUsd": 0.0004,
"worthClaiming": null,
"caveats": [
"Pending TINY restake rewards are not collected on positions; claim via manage shape."
]
}
],
"protocols": [
{
"protocol": "tinyman",
"status": "ok",
"positionCount": 1,
"message": null
},
{
"protocol": "compx",
"status": "ok",
"positionCount": 1,
"message": null
},
{
"protocol": "pact",
"status": "ok",
"positionCount": 0,
"message": null
},
{
"protocol": "haystack",
"status": "ok",
"positionCount": 2,
"message": null
},
{
"protocol": "alpha-arcade",
"status": "ok",
"positionCount": 0,
"message": null
}
],
"totals": {
"claimableUsd": null,
"estimatedNetworkFeeUsd": 0.0514,
"worthClaimingUsd": null
},
"claimAllQuotes": {
"quotes": [
{
"shapeKey": "mainnet:haystack:v1:claim:rewards",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"
}
},
{
"shapeKey": "mainnet:compx:v1:claim:rewards",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ",
"poolAppId": 123456
}
},
{
"shapeKey": "mainnet:tinyman:restake-v1:claimRewards:stAlgo",
"input": {
"userAddress": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"
}
}
]
},
"meta": {
"address": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ",
"fetchedAt": "2026-08-13T12:00:00.000Z",
"algoUsd": 0.2,
"paymentRequired": true
}
} Haystack swaps (quote → opt-in → paid transactions)
Walletless swap flow. Amounts are integer asset base units. Free quote and opt-in; paid
POST /swaps/transactions (~0.005 USDC). Canix never signs or submits.
1) Free quote
curl -i https://canix402-api.compx.io/swaps/quote \
-H 'content-type: application/json' \
-d '{
"address": "YOUR_ALGORAND_ADDRESS",
"fromAssetId": 0,
"toAssetId": 31566704,
"amount": "1000000",
"type": "fixed-input"
}' Sample quote response (200)
{
"data": {
"address": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"fromAssetId": "0",
"toAssetId": "31566704",
"amount": "1000000",
"type": "fixed-input",
"quotedAmount": "185000",
"createdAt": "2026-07-30T12:00:00.000Z",
"expiresAt": "2026-07-30T12:02:00.000Z",
"priceBaseline": 0.185,
"usdIn": 0.2,
"usdOut": 0.185,
"requiredAppOptIns": [
1234567890
],
"route": [
{
"protocol": "tinyman",
"poolId": "1002541853"
}
],
"quotes": [],
"protocolFees": [],
"txnPayload": "<opaque-haystack-quote-blob>",
"note": "Pass this quote object unchanged to /swaps/optin and /swaps/transactions. Refresh after any opt-in submit."
},
"meta": {
"paymentRequired": false,
"executionSubmitted": false
}
} 2) Free opt-in (pass quote unchanged)
curl -i https://canix402-api.compx.io/swaps/optin \
-H 'content-type: application/json' \
-d '{
"address": "YOUR_ALGORAND_ADDRESS",
"quote": { /* full data object from /swaps/quote */ }
}' Sample opt-in response (200)
{
"data": {
"required": true,
"transactions": [
{
"type": "axfer",
"note": "asset opt-in for toAssetId",
"encoded": "<base64-unsigned-txn-0>"
},
{
"type": "appl",
"note": "application opt-in for requiredAppOptIns[0]",
"encoded": "<base64-unsigned-txn-1>"
}
],
"userSignIndexes": [
0,
1
],
"createdAt": "2026-07-30T12:00:05.000Z",
"expiresAt": "2026-07-30T12:02:00.000Z"
},
"meta": {
"paymentRequired": false,
"executionSubmitted": false,
"note": "Empty transactions[] means no opt-ins are missing. Sign and submit locally, then fetch a fresh quote before /swaps/transactions."
}
}
If transactions is non-empty, sign and submit locally, wait for confirmation, then
fetch a fresh quote before the paid step.
3) Paid transactions — preflight (expect 402)
curl -i https://canix402-api.compx.io/swaps/transactions \
-H 'content-type: application/json' \
-d '{
"address": "YOUR_ALGORAND_ADDRESS",
"quote": { /* fresh quote data object */ },
"slippage": 0.005
}' 4) Paid transactions — retry with PAYMENT-SIGNATURE
curl -i https://canix402-api.compx.io/swaps/transactions \
-H 'content-type: application/json' \
-H 'PAYMENT-SIGNATURE: <base64-json-payload>' \
-d '{
"address": "YOUR_ALGORAND_ADDRESS",
"quote": { /* fresh quote data object */ },
"slippage": 0.005
}' Sample transactions response (200)
{
"data": {
"encodedTransactions": [
"<base64-txn-0-user-sign>",
"<base64-txn-1-haystack-presigned>",
"<base64-txn-2-user-sign>"
],
"userSignIndexes": [
0,
2
],
"createdAt": "2026-07-30T12:00:30.000Z",
"expiresAt": "2026-07-30T12:02:00.000Z",
"note": "Sign only userSignIndexes members. Preserve Haystack pre-signed members and atomic group order. Submit the complete group via your own Algod client."
},
"meta": {
"paymentRequired": true,
"executionSubmitted": false
}
}
Sign only userSignIndexes, keep Haystack pre-signed members and group order, then
submit the complete atomic group through your own Algod client.
Error responses
Paid routes return 402 before payment; validation and server errors use a stable envelope.
402 — payment required
{
"error": {
"code": "MISSING_PAYMENT_SIGNATURE",
"message": "The paid endpoint was called without PAYMENT-SIGNATURE."
}
} 400 — invalid Algorand address (personalized route)
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Query parameter 'address' is not a valid Algorand address."
}
}