Skip to main content
Alpha feature: Advanced Order Triggers are gated and not publicly available yet. Reach out to the Mobula team to enable access for your account.
Trigger Advanced Orders execute when a Token Details condition becomes true, then quote and route the swap through Mobula. Use them for token security checks, liquidity thresholds, volume conditions, holder concentration limits, metadata checks, or custom automated trading rules based on getTokenData. Mobula confirms the trigger through Token Details first, then builds a fresh swap quote and still enforces minAmountOutRaw before sending.

POST / GET

MethodPathPurpose
POST/api/2/swap/advanced-orders/intentBuild the canonical intent message to sign.
POST/api/2/swap/advanced-ordersCreate the signed order.
GET/api/2/swap/advanced-ordersList owner orders. Requires a read signature.
GET/api/2/swap/advanced-orders/:orderIdRead one order. Requires a read signature.
POST/api/2/swap/advanced-orders/:orderId/cancelCancel an open or triggered order.

End-to-End Flow

Advanced Orders are deposit-backed intents. The user keeps custody of their wallet keys and never gives Mobula a reusable approval, session key, or delegated signing power. The only funds Mobula can execute with are the exact tokens the user transfers to the Mobula deposit wallet for that order.
The deposited amount is held in the Mobula deposit wallet while the order is open. If the order is cancelled, expires, or cannot execute, the settlement flow refunds the confirmed deposit to the owner.
StepActorWhat happens
1IntegratorUse the Mobula-provided deposit wallet for the environment. The end user must not choose this address.
2User walletTransfer exactly amountRaw of tokenIn from ownerAddress to the Mobula deposit wallet.
3ClientCall POST /api/2/swap/advanced-orders/intent with the deposit transaction hash and all order parameters.
4Mobula APINormalizes the payload, resolves the server deposit wallet, validates addresses and amounts, then returns the canonical message to sign.
5User walletSigns the canonical message. This signature covers the chain, owner, recipient, tokens, amounts, trigger settings, expiry, deposit transaction, routing restrictions, and fees.
6ClientCall POST /api/2/swap/advanced-orders with the same fields plus intentSignature.
7Mobula APIVerifies the owner signature and stores the order idempotently by intent hash.
8Mobula workerPolls open orders every few seconds and verifies the deposit transaction on-chain. The deposit must be finalized, successful, sent by ownerAddress, sent to the Mobula deposit wallet, and match tokenIn + amountRaw.
9Mobula workerWatches swaps-stream for relevant token/pair updates. For TP/SL it pre-checks quote movement; for Triggers it confirms the configured Token Details fields through getTokenData.
10Mobula execution engineClaims the order, builds a fresh quote with the order constraints, checks minAmountOutRaw, signs only the swap transaction for the deposit wallet, and broadcasts it.
11Mobula settlementConfirms the broadcasted transaction. If filled, output funds are sent to recipientAddress. If cancelled, expired, or non-executable, the confirmed deposit is refunded to ownerAddress.

Non-Custodial Guarantees

GuaranteeHow it is enforced
Mobula cannot trade from the user’s walletThe user only signs an intent message, not a transaction spending future wallet balances.
Mobula cannot mutate the order after signingThe canonical message includes the full order payload. Changing any signed field changes the intent hash and invalidates the signature.
Mobula cannot use a different depositDeposit verification checks the exact finalized transfer: owner, deposit wallet, token, and raw amount.
Mobula cannot bypass the output guardExecution always checks the fresh quote against minAmountOutRaw before sending.
The user can exit before executionThe owner can cancel open/triggered orders with a signed cancel message. Confirmed deposits are then handled by the refund settlement flow.

Client Checklist

  1. Build and send the token transfer to the Mobula deposit wallet.
  2. Wait for the deposit transaction signature.
  3. Call POST /advanced-orders/intent.
  4. Ask the owner wallet to sign data.message.
  5. Call POST /advanced-orders with intentSignature.
  6. Poll GET /advanced-orders or GET /advanced-orders/:orderId.
  7. To cancel, sign the canonical cancel message and call POST /advanced-orders/:orderId/cancel.

Trigger Order Model

type AdvancedOrderTriggerOperator =
  | "equals"
  | "not"
  | "gt"
  | "gte"
  | "lt"
  | "lte"
  | "in"
  | "contains"
  | "startsWith"
  | "endsWith"
  | "exists";

type AdvancedOrderFieldTrigger = {
  token?: "in" | "out"; // defaults to "in"
  field: string;
  operator: AdvancedOrderTriggerOperator;
  value?: string | number | boolean | null | Array<string | number | boolean | null>;
};

type AdvancedOrderTriggerExpression =
  | AdvancedOrderFieldTrigger
  | { all: AdvancedOrderTriggerExpression[] }
  | { any: AdvancedOrderTriggerExpression[] }
  | { not: AdvancedOrderTriggerExpression };
No source field is used. A trigger can only reference fields returned by Token Details for tokenIn or tokenOut.

Supported Token Details Fields

Use top-level fields returned by GET /api/2/token/details, plus the explicit security.* fields below.
CategoryFields
Identityaddress, chainId, symbol, name, decimals, id, tokenType
Price / liquiditypriceUSD, priceToken, approximateReserveUSD, approximateReserveToken, liquidityUSD, liquidityMaxUSD, marketCapUSD, marketCapDilutedUSD
Price changepriceChange1minPercentage, priceChange5minPercentage, priceChange1hPercentage, priceChange4hPercentage, priceChange6hPercentage, priceChange12hPercentage, priceChange24hPercentage
Volumevolume1minUSD, volume5minUSD, volume15minUSD, volume1hUSD, volume4hUSD, volume6hUSD, volume12hUSD, volume24hUSD, volumeBuy*USD, volumeSell*USD
Tradestrades*, buys*, sells*, buyers*, sellers*, traders* for supported timeframes
OrganicorganicTrades*, organicVolume*USD, organicBuys*, organicSells*, organicBuyers*, organicSellers*, organicTraders*
Fees / trendingfeesPaid*USD, totalFeesPaidUSD, trendingScore*, surgeScore
HoldersholdersCount, top10HoldingsPercentage, top50HoldingsPercentage, top100HoldingsPercentage, top200HoldingsPercentage, devHoldingsPercentage, insidersHoldingsPercentage, bundlersHoldingsPercentage, snipersHoldingsPercentage
Token statebonded, bondingPercentage, bondingCurveAddress, poolAddress, source, factory, sourceFactory, deployer, createdAt, latestTradeDate, bondedAt
Social / listingsocials.twitter, socials.website, socials.telegram, twitterReusesCount, twitterRenameCount, dexscreenerListed, dexscreenerAdPaid, dexscreenerSocialPaid, dexscreenerBoosted
Securitysecurity.buyTax, security.sellTax, security.transferTax, security.transferPausable, security.top10Holders, security.isBlacklisted, security.isHoneypot, security.isNotOpenSource, security.renounced, security.locked, security.isWhitelisted, security.balanceMutable, security.lowLiquidity, security.burnRate, security.isMintable, security.modifyableTax, security.selfDestruct, security.liquidityBurnPercentage, security.noMintAuthority, security.isFreezable
Fields that are not returned by getTokenData are not accepted. This excludes pool.* filters, Pulse aliases, and Token Filters-only fields that do not exist in Token Details.

Trigger Intent Body

{
  "chainId": "solana:solana",
  "ownerAddress": "<OWNER>",
  "recipientAddress": "<OWNER>",
  "tokenIn": "<TOKEN_MINT>",
  "tokenOut": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "amountRaw": "1000000000",
  "minAmountOutRaw": "830000",
  "triggerAmountOutRaw": "1",
  "triggerDirection": "gte",
  "orderKind": "limit",
  "slippage": 2,
  "depositTransactionHash": "<DEPOSIT_TX_SIGNATURE>",
  "expiresAt": "2026-08-01T00:00:00.000Z",
  "onlyRouters": ["mobula"],
  "triggers": {
    "all": [
      { "field": "volume24hUSD", "operator": "gte", "value": 10000 },
      { "field": "security.noMintAuthority", "operator": "equals", "value": true },
      { "field": "security.isFreezable", "operator": "equals", "value": false }
    ]
  }
}
triggerAmountOutRaw and triggerDirection remain required for compatibility, but when triggers is present the trigger condition is the triggers expression. minAmountOutRaw remains the final quote guard.

Create a Trigger Order

const intent = await fetch("https://api.mobula.io/api/2/swap/advanced-orders/intent", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": "<YOUR_API_KEY>",
  },
  body: JSON.stringify(intentBody),
}).then((res) => res.json());

const intentSignature = await wallet.signMessage(intent.data.message);

await fetch("https://api.mobula.io/api/2/swap/advanced-orders", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": "<YOUR_API_KEY>",
  },
  body: JSON.stringify({ ...intentBody, intentSignature }),
});

Read

curl "https://api.mobula.io/api/2/swap/advanced-orders?ownerAddress=<OWNER>&readSignature=<SIGNATURE>" \
  -H "x-api-key: <YOUR_API_KEY>"