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

# Funding intents

> A request for value, and the lifecycle it moves through until you are credited.

A funding intent is your application's request to receive an exact amount of an exact asset at
an exact destination. It is registered on the Useroutr Soroban protocol when you create it, and
it only ever moves forward through a fixed lifecycle.

## Create one

```ts theme={null}
const intent = await useroutr.fundingIntents.create(
  {
    amount: "25",
    asset: "asset_usdc_stellar",
    reference: "ORDER-1042",
    metadata: { plan: "pro", seats: 5 },
  },
  { idempotencyKey: "ORDER-1042" },
);
```

<ParamField body="amount" type="string" required>
  A positive decimal string within the asset's precision, for example `"25"` or `"12.5"`. Never a
  float.
</ParamField>

<ParamField body="asset" type="string" required>
  An asset id from `useroutr.assets.list()`, such as `asset_usdc_stellar`. See
  [Assets and networks](/concepts/assets-and-networks).
</ParamField>

<ParamField body="destination" type="object">
  Where the value settles: `{ network, asset, address }`. Defaults to your application's default
  destination. It must be on the asset's own network and for the same asset. A Stellar account
  must already exist and, for an issued asset such as USDC, hold a trustline for it; otherwise the
  request is refused with `INVALID_DESTINATION` rather than taking a payment that could not be
  delivered.
</ParamField>

<ParamField body="reference" type="string">
  Your own id, up to 255 characters, returned unchanged. Your order id is a good choice.
</ParamField>

<ParamField body="metadata" type="object">
  Up to 50 keys of strings, numbers, booleans or null, returned unchanged.
</ParamField>

<ParamField body="expires_at" type="string">
  ISO 8601. Defaults to 30 minutes from now, at most 24 hours.
</ParamField>

The idempotency key is required. The same key with the same body returns the original intent;
the same key with a different body is refused. See [Idempotency](/integrate/idempotency).

## Lifecycle

| Status | What it means | Webhook |
| - | - | - |
| `CREATED` | Created; protocol registration in flight | `funding.created` |
| `AWAITING_PAYMENT` | Registered; `funding_instructions` are ready to show | |
| `PARTIALLY_FUNDED` | Payments so far are below the amount; instructions ask for the rest | `funding.partially_funded` |
| `PAYMENT_CONFIRMED` | A valid payment covering the amount was verified | `funding.payment_confirmed` |
| `SETTLING` | A settlement is being driven on the protocol | `funding.settling` |
| `SETTLED` | The settlement was confirmed against chain state | `funding.settled` |
| `CREDITED` | The ledger credit is posted. You have been paid. | `funding.credited` |
| `EXPIRED` | `expires_at` passed before it was funded. Set once Useroutr has checked the chain up to `expires_at`, so a payment made in time is never lost to expiry. | `funding.expired` |
| `FAILED` | Registration or settlement failed; see `failure` | `funding.failed` |

`PAYMENT_DETECTED` and `ROUTING` happen inside the steps that confirm a payment and create a
settlement, so you never observe them. `CANCELLED`, `REFUND_PENDING` and `REFUNDED` are defined
for flows that are not live yet; no intent reaches them today.

<Tip>Fulfil orders on `CREDITED`, never earlier. It is the only status that means the value is yours.</Tip>

## Funding instructions

Every intent gets a **deposit account**: a Stellar account Useroutr creates for that intent
alone. It is not your destination; your destination receives the value once the payment
settles.

While the intent is `AWAITING_PAYMENT` or `PARTIALLY_FUNDED`, `funding_instructions` tells your
user exactly what to send:

```json theme={null}
{
  "network": "stellar",
  "stellar_network": "testnet",
  "deposit": { "address": "GCLPHLWOSOZNS7T2CPP6KA36V6QKMLXZETKPTY523PIQTOWL7IMWP6IH", "type": "account" },
  "asset": { "id": "asset_xlm_stellar", "symbol": "XLM", "stellar_asset": "native", "decimals": 7 },
  "amount": "10.0000000",
  "required_amount": "10.0000000",
  "received_amount": "0.0000000",
  "expires_at": "2026-09-26T11:53:53.000Z"
}
```

No memo is needed: the address alone identifies the intent.

## Partial payments and overpayments

Payments add up. A smaller payment moves the intent to `PARTIALLY_FUNDED` and the instructions
ask for the remainder. Once the total reaches the amount, the intent is `PAYMENT_CONFIRMED`.

Anything above the amount is never credited. It is recorded as a refund with reason
`OVERPAYMENT` and paid back to the payer. Payments that do not match, such as the wrong asset or
a payment after expiry, are recorded as rejected and fire `payment.rejected`, and the intent
keeps waiting. See [Refunds](/guides/refunds).

## Read

```ts theme={null}
const intent = await useroutr.fundingIntents.retrieve("fi_2d6a91c4");
const { data: payments } = await useroutr.fundingIntents.listPayments(intent.id);

for await (const credited of useroutr.fundingIntents.iterate({ status: "CREDITED" })) {
  console.log(credited.reference);
}
```

The intent carries its `payment` and `settlement` once they exist, `hosted_funding_url` for the
payer, and while a quote is locked, its `source`, `quote` and `route`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.