Skip to main content
An ad is a maker’s standing offer on one route: funds escrowed in the AdManager on the ad chain, paid out to bridgers who pay the order token on the other chain. These endpoints let anyone browse ads and let a maker prepare every change to their own. See Liquidity ads for the concept.

Endpoints

Who may act on an ad

Every write on an ad passes the same check:
  1. You must have a signed-in wallet of the ad chain’s kind (EVM or STELLAR). Otherwise the relayer answers 403 with No STELLAR wallet linked — connect and link the matching wallet to continue (or EVM).
  2. If the ad’s creator is that wallet, you may act (creatorKind: "WALLET").
  3. Otherwise the creator must be an account you linked (a Stellar agent account, or an EVM custody account, see Accounts), and the chain must say right now that its owner is your signed-in wallet. The owner is read from the chain on every write.
GET /v1/ads/mine uses a lighter rule: your stored wallets and links, with no chain read.

Agent-account makers

A maker can run an ad through an agent account instead of a wallet (see Agents). Then creatorKind is STELLAR_AGENT_ACCOUNT or EVM_CUSTODY_ACCOUNT, creator is the account and authorizer is its owner, your signed-in wallet. The wallet calls the account’s own functions rather than the AdManager directly: create_ad, fund_ad and call on Stellar, createAdFunded, fundAdFunded and execute on EVM. Calls that move money pay from the wallet into the escrow in the same transaction. The account never holds funds.

Ad statuses

The read endpoints show EXHAUSTED for any ad that is not INACTIVE or CLOSED and has availableAmount 0. The status filter, and the trade path, use the stored status. A fund, withdraw or close on an ACTIVE ad pauses it at once, so no trade starts against a pool that is about to change. When the change confirms, the ad goes back to its earlier status (or to EXHAUSTED after a withdraw that leaves nothing free, or CLOSED after a close). If the change never lands, the relayer restores the earlier status. A create that never lands ends as CLOSED.

What the relayer returns, and what the wallet sends

The relayer signs nothing for an ad. Each write returns the contract call’s arguments, shaped for the ad chain. Your wallet builds and sends the transaction, and the relayer checks the chain afterwards. adId is a UUID the relayer picks at create. It is both the relayer’s id and the on-chain ad id.

The settlement signer

Every ad names a settlement signer: the account whose BLS key co-signs settlements for the maker (see Settlement keys). It defaults to the creator. An agent account holds no key, so an ad created from one must name a signer. The signer must hold a usable key on the ad chain’s registry when you create the ad, or the AdManager refuses it on chain. To re-point it later, the maker calls setSettlementSigner(adId, identity) (set_settlement_signer on Stellar) directly; there is no relayer route for it.

Browse ads

GET /v1/ads lists ads, ordered by id. Pass nextCursor as cursor for the next page.
  • routeStatus defaults to ACTIVE when you browse, so ads on retired routes are hidden. With a creator filter it defaults to ALL, so a maker still sees an ad on a retired route to withdraw from and close it.
  • With no status, inactive and closed ads are listed too. A marketplace should pass status=ACTIVE and hide rows whose availableAmount is 0.

My ads

GET /v1/ads/mine takes the same query and returns the same shape, limited to ads whose creator is one of your wallets or linked accounts. Any creator filter you send is replaced. This is where you see your own INACTIVE and CLOSED ads, and ads on retired routes (send routeStatus=ACTIVE to hide them). With no wallet and no link you get { "data": [], "nextCursor": null }.

One ad

GET /v1/ads/:id returns one ad in the same shape as a list row. An ad on a retired route still answers, with routeStatus: "RETIRED": its maker can fund, withdraw and close it, but it takes no new trades.

Create an ad

POST /v1/ads/create checks the route, the amounts, the creator and the settlement signer, writes the ad as INACTIVE and returns the createAd call.
creatorDstAddress is a payout destination, not an identity, so it need not be a wallet you linked. Send minAmount and maxAmount together or not at all: minAmount alone is refused.
Send the call, then confirm it.

Fund and withdraw

POST /v1/ads/:id/fund and POST /v1/ads/:id/withdraw read the ad on chain, record the pending change, pause an ACTIVE ad and return the call.
You can withdraw only what is free on chain: the balance, less locked amounts, less trade reservations not yet locked. Only one change can be pending per ad. If an earlier change already landed but was never confirmed, the answer is { "pendingConfirmation": true, "chainKind": "EVM" }: call confirm, then send the request again.

Fetch the pending call again

POST /v1/ads/:id/action-data re-serves the arguments of a pending create or fund, for a wallet popup that was closed. It takes no body and makes no new pending record. A pending withdraw or close is not re-served: wait for it to clear and start again.
It does not check whether the call already landed, and sending a landed create again reverts. If the user may have signed, call confirm first.

Confirm a landed transaction

POST /v1/ads/:id/confirm checks the chain against the pending change. The relayer does not look up your transaction: txHash is optional and not read, so {} is a valid body.
A create has landed when the ad exists on chain with the right maker, signer and balance. A fund or withdraw has landed when the AdManager’s own event for this ad and amount appears after the quote; on EVM it must be EVM_CONFIRMATIONS blocks deep. A close has landed when the ad is no longer open. On confirm the relayer copies the chain’s balance into poolAmount and applies the recorded status. If a create landed after the relayer gave up on it and closed the row, confirm still finds it on chain and restores the ad to ACTIVE. A change that is never confirmed is not lost. The relayer checks stale pending changes on chain and applies or clears them itself.

Update limits, metadata or pause

PATCH /v1/ads/:id/update changes relayer-side settings. There is no transaction and the change takes effect at once. The on-chain ad has no minimum, maximum or pause; these settings shape what the relayer offers bridgers.
Limits and metadata are editable in every status. A status change is refused on an INACTIVE or CLOSED ad. On an EXHAUSTED ad the relayer reads the chain and allows it only when funds are free there. The relayer does not check minAmount ≤ maxAmount here, so check it in your form, and offer pause and resume only on ACTIVE or PAUSED ads with no pending change.

Close an ad

POST /v1/ads/:id/close returns the closeAd call, which pays the whole on-chain balance to to. Close is refused while any trade holds liquidity on the ad, locked on chain or reserved.
Like fund and withdraw, it can answer { "pendingConfirmation": true, … } when an earlier change landed unconfirmed, and it shares their pending-change and chain refusals.

Liquidity held by trades

When a bridger creates a trade, the relayer holds that amount of the ad. availableAmount drops by it, a withdraw cannot take it, and close is refused. The hold ends when the trade settles or is cancelled, or when an unfunded reservation expires after 30 minutes. Because the relayer copies the chain’s balance after each settlement, poolAmount can change without any action from you: a completed trade lowers it.