> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mobula.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Bridge Intents

> [Alpha Preview] List bridge intents with cursor pagination — newest-first, or oldest-first to tail the feed.

<Warning>
  **Alpha Preview** — Endpoints and response shape may change without notice.
</Warning>

Paginated history of bridge intents — every bridge attempt with its lifecycle
status, amounts (raw + USD), token metadata, itemized fees, transaction hashes,
and per-step timestamps. Newest-first by default; pass `order=asc` to walk it
forward from a watermark (see [Following the feed](#following-the-feed)).

## Scoping

At least one scoping dimension is required — the endpoint never runs an
unbounded scan:

* `wallet` — intents **sent** by that address (the depositor).
* `customerId` — intents created with any API key owned by that customer.
* `apiKey` — intents created with that specific API key.
* `intentId` — a single intent; it scopes on its own, since the id is unique.

`customerId` and `apiKey` are mutually exclusive (at most one). `wallet` can be
combined with either to narrow a customer/key scope to one address.

Note that `apiKey` is both the auth credential and a scope: passing
`?apiKey=` filters results to intents created with that key. To list a
wallet's intents across **all** keys, authenticate with the
`Authorization: <key>` header and pass only `wallet`. An unknown or revoked
`apiKey` returns `404`.

## Query parameters

| Name                 | Required        | Notes                                                                                                                               |
| -------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `wallet`             | one of the four | Sending address. EVM hex or Solana base58.                                                                                          |
| `customerId`         | one of the four | All intents from keys owned by this customer.                                                                                       |
| `apiKey`             | one of the four | Intents created with this key.                                                                                                      |
| `intentId`           | one of the four | The single intent with this id. Use it to re-read one intent — a dead-letter retry, say — instead of re-paging the feed.            |
| `status`             | no              | Filter by lifecycle status (see table below).                                                                                       |
| `originChainId`      | no              | Chain id, name, or alias — `evm:8453`, `base`, `8453` all work.                                                                     |
| `destinationChainId` | no              | Same formats as `originChainId`.                                                                                                    |
| `createdAfter`       | no              | Only intents created **strictly after** this time. Accepts epoch seconds, epoch milliseconds (what `createdAt` emits), or ISO-8601. |
| `createdBefore`      | no              | Only intents created **at or before** this time. Same formats.                                                                      |
| `order`              | no              | `desc` (newest-first, the default) or `asc` (oldest-first).                                                                         |
| `limit`              | no              | Page size, 1–100. Default `50`.                                                                                                     |
| `cursor`             | no              | Opaque, from the previous page's `pagination.nextCursor` or `pagination.resumeCursor`.                                              |

Unknown chains, malformed wallets, malformed cursors, and unparseable
`createdAfter` / `createdBefore` values return `400`.

## Response

```json theme={null}
{
  "data": [
    {
      "intentId": "52ec786-5ddbe3f-dff",
      "status": "filled",
      "originChainId": "evm:42161",
      "destinationChainId": "solana:solana",
      "sender": "0xa57c9583d1656a6cbb0c62c3a6c7b264f644ac25",
      "recipient": "2ytTkFGy8EpbrRY56kjKQ6L1hmqCqbuQArqd6VeNyJK1",
      "originToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
      "originMeta": { "name": "USDC", "symbol": "USDC", "logo": "https://metadata.mobula.io/assets/logos/...", "decimals": 6 },
      "inputToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
      "inputMeta": { "name": "USDC", "symbol": "USDC", "logo": "https://metadata.mobula.io/assets/logos/...", "decimals": 6 },
      "inputAmount": "7887660",
      "destinationToken": "B4ptaVsUe6YbtBwAS38WFeweSrVNfQLCcj9JRrtjU8vn",
      "destinationMeta": { "name": "SOLdiers", "symbol": "SOLDIERS", "logo": "https://metadata.mobula.io/assets/logos/...", "decimals": 6 },
      "amountIn": "7887660",
      "amountOut": "7881497",
      "amountInUsd": 7.88766,
      "amountOutUsd": 7.881497,
      "depositTxHash": "0xabd6e3210b9f495921bf1b096a8fe48dccaa3348bce45ab8ec901c4229528aec",
      "fillTxHash": "5xL...",
      "settleTxHash": "0x1d967fe2f6ab1ec1d8596b2faf80bcec3ccc341e61c6fddb34d9dd2b710dced6",
      "refundTxHash": null,
      "latencyMs": 487,
      "timestamps": {
        "depositDetected": 1784183450897,
        "fillSent": 1784183451200,
        "fillConfirmed": 1784183451384,
        "settled": 1784183452168
      },
      "fees": {
        "bridgeBps": 5,
        "bridgeUsd": 0.003944,
        "integratorAddress": "0x1234...",
        "integratorUsd": 0.09
      },
      "createdAt": 1784183450000
    }
  ],
  "pagination": {
    "limit": 50,
    "pageEntries": 1,
    "nextCursor": null,
    "resumeCursor": "MjAyNi0wNi0yNFQxMzo0Njo0Mi44MzNafGNhMmYw..."
  }
}
```

Two differences from `/status/{id}` worth flagging:

* `amountIn` / `amountOut` are **raw base units** (not decimal-adjusted) —
  `"7887660"` above is 7.88766 USDC. Divide by `originMeta.decimals` /
  `destinationMeta.decimals` to display, or use `amountInUsd` / `amountOutUsd`.
* Timestamps are **epoch milliseconds**, not ISO strings.

`originMeta` / `destinationMeta` / `inputMeta` carry token name/symbol/logo/decimals,
with `null` fields when the token isn't indexed. `latencyMs` is the
deposit-detected → fill-confirmed delta (null when the intent never filled,
e.g. a refund).

### The token the user sold

Bridging **from a token the bridge does not hold** — anything but the native
coin or USDC on that chain — swaps it first: the helper sells it for the origin
chain's native coin, and only then does the bridge see the funds. `originToken`
is therefore the native coin, because that is what the bridge received and what
a refund would return.

`inputToken` / `inputMeta` / `inputAmount` describe the leg before that swap —
what the user actually parted with:

```json theme={null}
{
  "originToken": "0x0000000000000000000000000000000000000000",
  "originMeta": { "symbol": "ETH", "decimals": 18 },
  "amountIn": "411241372356736",
  "inputToken": "0x18c11FD286C5EC11c3b683Caa813B77f5163A122",
  "inputMeta": { "symbol": "GNS", "decimals": 18 },
  "inputAmount": "1818901713804608659"
}
```

Read as: sold 1.8189 GNS, which became 0.000411 ETH, which is what got bridged.

When no swap was needed, `inputToken` equals `originToken` and `inputAmount`
equals `amountIn`. Both are `null` on intents created before these fields
existed — fall back to `originToken` / `amountIn` there; they are never
backfilled.

### Refunds

A bridge that cannot deliver returns the deposit on the origin chain.
`refundTxHash` is that transaction, and `status` is `refunded`.

Two things to know when rendering one:

* The refunded amount is in `amountOut`, denominated in the **origin** token
  (`originToken` / `originMeta`) — not the destination token it normally holds.
  It is the deposit minus the refund's gas.
* A swapped deposit is refunded in what the bridge held, so a user who sold GNS
  is paid back in ETH. The swap already happened on chain and cannot be undone.

`refundTxHash` is `null` on every intent that was not refunded.

### Fees

`fees` itemizes what was already deducted — the amounts in `amountOut` /
`amountOutUsd` are net of all of it:

| Field               | Meaning                                                         |
| ------------------- | --------------------------------------------------------------- |
| `bridgeBps`         | Mobula protocol fee in basis points, as applied to this intent. |
| `bridgeUsd`         | That fee in USD (`bridgeBps` applied to `amountInUsd`).         |
| `integratorAddress` | The integrator's payout address, when the quote carried one.    |
| `integratorUsd`     | The integrator's cut in USD.                                    |

`integratorAddress` / `integratorUsd` are `null` on intents quoted without an
integrator fee. Destination gas is not itemized here — it is priced into the
quote, not charged as a fee line.

### Destination before the fill

Until the fill lands, `destinationToken` and `recipient` are **chain-shaped
placeholders**, not the real values — the destination of an unfilled intent
describes a trade the solver still has to execute. They become real on
`filled`, `settling`, `settled`, `settle_lost`, `refunded`, and `failed`. Treat
a non-terminal row's destination as unknown rather than storing it.

## Status lifecycle

Happy path: `pending → deposited → filling (→ broadcasted → replaced) → filled
→ settling → settled`. Failure path: `filling → retrying → refunded` or
`failed`; `settling → settle_lost` when reconciliation could not confirm
settlement. From the user's perspective, `filled` (and later `settled`) means
funds were received; `refunded` means the deposit was returned on the origin
chain. See [Bridge Status](/rest-api-reference/endpoint/bridge-status) for the
statuses the live polling endpoint emits.

## Pagination

Cursor-based (keyset) on `(createdAt, id)`, in whichever `order` you asked for.
The cursor is opaque — pass it straight back, and keep `order` identical across
the pages of one scan or it will walk the wrong way.

* `nextCursor` is non-null only when the page came back **full**, meaning there
  is at least one more page. `null` means you've reached the end of the scan.
* `resumeCursor` marks where the page **stopped**, and is set whenever the page
  returned a row — including a partial one. It is what a follower resumes from;
  deriving a position from `createdAt` instead loses sub-millisecond ordering
  and can re-serve or skip a row.

```typescript theme={null}
const API = "https://api.mobula.io";
const KEY = "YOUR_API_KEY";

let cursor: string | null = null;
do {
  const url = new URL(`${API}/api/2/bridge/intents`);
  url.searchParams.set("apiKey", KEY);
  url.searchParams.set("wallet", "0xYourWallet");
  if (cursor) url.searchParams.set("cursor", cursor);

  const { data, pagination } = await (await fetch(url)).json();
  for (const intent of data) console.log(intent.intentId, intent.status);
  cursor = pagination.nextCursor;
} while (cursor);
```

## Following the feed

To keep an index in sync, page **forward** with `order=asc` and hold the last
`resumeCursor` as your watermark. Every cycle resumes exactly where the last
one stopped, so a cycle that returns nothing costs one request instead of
re-paging the whole history from the newest row down.

```typescript theme={null}
// `cursor` is your durable watermark — persist it, not a timestamp.
let cursor: string | null = loadWatermark();

for (;;) {
  const url = new URL(`${API}/api/2/bridge/intents`);
  url.searchParams.set("apiKey", KEY);
  url.searchParams.set("order", "asc");
  url.searchParams.set("limit", "100");
  if (cursor) url.searchParams.set("cursor", cursor);
  // Cold start only: begin at a point in time instead of the first intent ever.
  else url.searchParams.set("createdAfter", String(Date.now() - 24 * 3600 * 1000));

  const { data, pagination } = await (await fetch(url)).json();
  for (const intent of data) await index(intent);

  // Commit the watermark only after the rows are durably indexed.
  if (pagination.resumeCursor) { cursor = pagination.resumeCursor; saveWatermark(cursor); }
  if (!pagination.nextCursor) await sleep(2000); // caught up
}
```

`createdAfter` is inclusive of nothing — it is strictly greater-than — so a
timestamp cold start never re-delivers the row it names. Once you hold a
cursor, drop `createdAfter`: the cursor is the more precise position.


## OpenAPI

````yaml get /2/bridge/intents
openapi: 3.0.0
info:
  version: 1.0.0
  title: Mobula API
  description: >-
    Documentation of the Mobula API


    **Demo API**: The default server (demo-api.mobula.io) is a demo API with
    rate limits.

    For production use, please use api.mobula.io with an API key from
    https://admin.mobula.io
servers:
  - url: https://demo-api.mobula.io/api/
    description: Demo API (rate limited, for testing only)
  - url: https://api.mobula.io/api/
    description: Production API (requires API key)
security: []
tags:
  - name: V2 - Token
    description: Token details, price, security, ATH, and holder data
  - name: V2 - Market Data
    description: Market details, OHLCV history, and lighthouse metrics
  - name: V2 - Trades
    description: Token trades, enriched trades, and trade filters
  - name: V2 - Wallet
    description: Wallet positions, activity, trades, analysis, and labels
  - name: V2 - Assets
    description: Cross-chain asset details and price history
  - name: V2 - Swap
    description: Swap quoting and execution
  - name: V2 - Perps
    description: Perpetual futures quoting, execution, and positions
  - name: V2 - Bridge
    description: Cross-chain bridge quoting and intent status (Alpha Preview)
  - name: V2 - DeFi
    description: Bonding pools and pulse data
  - name: V2 - Search
    description: Universal fast search
  - name: V2 - Usage
    description: Per-key API and WebSocket usage history
  - name: V2 - Blockchains
    description: System metadata and chain listings
  - name: V2 - Prediction Markets
    description: >-
      Polymarket markets/events, wallet positions, and the full execution stack
      (auth, order build/submit/cancel, approvals, pUSD wrap/unwrap, deploy,
      deposit/withdraw, redeem). Alpha — see /api/2/pm/*.
  - name: V1 - Market Data
    description: Market prices, history, sparklines, pairs, and multi-data
  - name: V1 - Wallet
    description: Wallet portfolio, transactions, history, and NFTs
  - name: V1 - Token
    description: First buyers
  - name: V1 - Trades
    description: Market trades by pair
  - name: V1 - Metadata
    description: Token metadata, categories, and news
  - name: V1 - Assets
    description: List all assets
  - name: V1 - Search
    description: Search for assets, tokens, and pairs
  - name: V1 - DeFi
    description: Bonding pool pulse data
  - name: V1 - Blockchains
    description: Blockchain listings, pairs, and stats
  - name: V1 - Webhooks
    description: Webhook management
  - name: V1 - Feed
    description: Custom feed creation
paths:
  /2/bridge/intents:
    get:
      tags:
        - V2 - Bridge
      summary: List bridge intents
      description: >-
        [Alpha Preview] Paginated bridge-intent history, newest-first by
        default. Scope by wallet (the sending address), by customerId (all
        intents created with keys owned by that customer), by apiKey (intents
        created with that key), or by intentId — at least one is required;
        customerId and apiKey are mutually exclusive. Optionally filter by
        status, origin/destination chain, and creation time, sort oldest-first
        with order=asc to follow the feed forward from a watermark, and page
        with the opaque cursor from pagination.nextCursor.
      parameters:
        - schema:
            type: string
            description: >-
              Wallet address — returns intents this address sent (the
              depositor). Recipient-side lookups are not served here.
          required: false
          description: >-
            Wallet address — returns intents this address sent (the depositor).
            Recipient-side lookups are not served here.
          name: wallet
          in: query
        - schema:
            type: string
            description: Scope to all intents created with API keys owned by this customer.
          required: false
          description: Scope to all intents created with API keys owned by this customer.
          name: customerId
          in: query
        - schema:
            type: string
            description: Scope to intents created with this API key.
          required: false
          description: Scope to intents created with this API key.
          name: apiKey
          in: query
        - schema:
            type: string
            description: Return the single intent with this id.
          required: false
          description: Return the single intent with this id.
          name: intentId
          in: query
        - schema:
            type: string
            enum:
              - pending
              - deposited
              - filling
              - broadcasted
              - replaced
              - filled
              - settling
              - settled
              - settle_lost
              - retrying
              - refunded
              - failed
            description: Filter by lifecycle status.
          required: false
          description: Filter by lifecycle status.
          name: status
          in: query
        - schema:
            type: string
            description: >-
              Filter by origin chain (id, name, or alias — e.g. "evm:8453",
              "base").
          required: false
          description: >-
            Filter by origin chain (id, name, or alias — e.g. "evm:8453",
            "base").
          name: originChainId
          in: query
        - schema:
            type: string
            description: Filter by destination chain (id, name, or alias).
          required: false
          description: Filter by destination chain (id, name, or alias).
          name: destinationChainId
          in: query
        - schema:
            type: string
            description: >-
              Only intents created strictly after this time — epoch seconds,
              epoch milliseconds, or ISO-8601. Pair with order=asc to page
              forward from a watermark.
          required: false
          description: >-
            Only intents created strictly after this time — epoch seconds, epoch
            milliseconds, or ISO-8601. Pair with order=asc to page forward from
            a watermark.
          name: createdAfter
          in: query
        - schema:
            type: string
            description: >-
              Only intents created at or before this time — epoch seconds, epoch
              milliseconds, or ISO-8601.
          required: false
          description: >-
            Only intents created at or before this time — epoch seconds, epoch
            milliseconds, or ISO-8601.
          name: createdBefore
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: >-
              Sort on creation time: desc (newest-first, default) or asc
              (oldest-first).
          required: false
          description: >-
            Sort on creation time: desc (newest-first, default) or asc
            (oldest-first).
          name: order
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: Page size (1-100, default 50).
          required: false
          description: Page size (1-100, default 50).
          name: limit
          in: query
        - schema:
            type: string
            description: >-
              Opaque cursor from the previous page's pagination.nextCursor. Keep
              order identical across pages of one scan.
          required: false
          description: >-
            Opaque cursor from the previous page's pagination.nextCursor. Keep
            order identical across pages of one scan.
          name: cursor
          in: query
      responses:
        '200':
          description: >-
            Bridge intents in the requested order, with cursor pagination.
            pagination.resumeCursor marks where a page stopped even when it was
            partial, so a follower can tail the feed; token meta carries
            decimals for the raw amounts, and fees itemizes the bridge and
            integrator cuts already deducted from amountOut.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        intentId:
                          type: string
                        status:
                          type: string
                          enum:
                            - pending
                            - deposited
                            - filling
                            - broadcasted
                            - replaced
                            - filled
                            - settling
                            - settled
                            - settle_lost
                            - retrying
                            - refunded
                            - failed
                        originChainId:
                          type: string
                        destinationChainId:
                          type: string
                        sender:
                          type: string
                        recipient:
                          type: string
                        originToken:
                          type: string
                        originMeta:
                          type: object
                          properties:
                            name:
                              type: string
                              nullable: true
                            symbol:
                              type: string
                              nullable: true
                            logo:
                              type: string
                              nullable: true
                            decimals:
                              type: integer
                              nullable: true
                          required:
                            - name
                            - symbol
                            - logo
                            - decimals
                        inputToken:
                          type: string
                          nullable: true
                          description: >-
                            Token the user actually bridged from; differs from
                            originToken on swap-and-bridge. Null on rows
                            predating the column.
                        inputMeta:
                          type: object
                          nullable: true
                          properties:
                            name:
                              type: string
                              nullable: true
                            symbol:
                              type: string
                              nullable: true
                            logo:
                              type: string
                              nullable: true
                            decimals:
                              type: integer
                              nullable: true
                          required:
                            - name
                            - symbol
                            - logo
                            - decimals
                        inputAmount:
                          type: string
                          nullable: true
                          description: >-
                            Raw amount sold, in inputToken's base units. Null
                            when the deposit was not a swap-and-bridge.
                        destinationToken:
                          type: string
                        destinationMeta:
                          type: object
                          properties:
                            name:
                              type: string
                              nullable: true
                            symbol:
                              type: string
                              nullable: true
                            logo:
                              type: string
                              nullable: true
                            decimals:
                              type: integer
                              nullable: true
                          required:
                            - name
                            - symbol
                            - logo
                            - decimals
                        amountIn:
                          type: string
                          description: >-
                            Raw amount in the origin token's base units (not
                            decimal-adjusted).
                        amountOut:
                          type: string
                          nullable: true
                          description: >-
                            Raw amount in the destination token's base units
                            (not decimal-adjusted). On a refunded intent this is
                            the amount returned to the sender, denominated in
                            the ORIGIN token — a swapped deposit is refunded in
                            what the bridge held.
                        amountInUsd:
                          type: number
                          nullable: true
                        amountOutUsd:
                          type: number
                          nullable: true
                        depositTxHash:
                          type: string
                          nullable: true
                        fillTxHash:
                          type: string
                          nullable: true
                        settleTxHash:
                          type: string
                          nullable: true
                        refundTxHash:
                          type: string
                          nullable: true
                          description: >-
                            Origin-chain refund tx, set once a failed intent has
                            been paid back.
                        latencyMs:
                          type: number
                          nullable: true
                        timestamps:
                          type: object
                          properties:
                            depositDetected:
                              type: number
                              nullable: true
                            fillSent:
                              type: number
                              nullable: true
                            fillConfirmed:
                              type: number
                              nullable: true
                            settled:
                              type: number
                              nullable: true
                          required:
                            - depositDetected
                            - fillSent
                            - fillConfirmed
                            - settled
                          description: Per-step timestamps, epoch milliseconds.
                        fees:
                          type: object
                          properties:
                            bridgeBps:
                              type: number
                              nullable: true
                            bridgeUsd:
                              type: number
                              nullable: true
                            integratorAddress:
                              type: string
                              nullable: true
                            integratorUsd:
                              type: number
                              nullable: true
                          required:
                            - bridgeBps
                            - bridgeUsd
                            - integratorAddress
                            - integratorUsd
                          description: >-
                            Fees already deducted from amountOut. bridgeUsd is
                            bridgeBps applied to amountInUsd.
                        createdAt:
                          type: number
                          description: Intent creation time, epoch milliseconds.
                      required:
                        - intentId
                        - status
                        - originChainId
                        - destinationChainId
                        - sender
                        - recipient
                        - originToken
                        - originMeta
                        - inputToken
                        - inputMeta
                        - inputAmount
                        - destinationToken
                        - destinationMeta
                        - amountIn
                        - amountOut
                        - amountInUsd
                        - amountOutUsd
                        - depositTxHash
                        - fillTxHash
                        - settleTxHash
                        - refundTxHash
                        - latencyMs
                        - timestamps
                        - fees
                        - createdAt
                  pagination:
                    type: object
                    properties:
                      limit:
                        type: number
                      pageEntries:
                        type: number
                      nextCursor:
                        type: string
                        nullable: true
                        description: Next full page; null once the feed is caught up.
                      resumeCursor:
                        type: string
                        nullable: true
                        description: >-
                          Where this page stopped, set whenever it returned a
                          row — including a partial one. A follower tailing the
                          feed resumes from it instead of re-deriving a position
                          from createdAt, which only has millisecond resolution.
                    required:
                      - limit
                      - pageEntries
                      - nextCursor
                      - resumeCursor
                required:
                  - data
                  - pagination

````