Stellar anchors vs a payout API: how SEP-24, SEP-31, and SEP-38 off-ramp USDC

How Stellar anchors off-ramp USDC through SEP-24, SEP-31, and SEP-38 quotes, how a payout API does the same job, and which one fits your product.

Stellar anchors and payout APIs both turn USDC on Stellar into money in a bank account. Anchors do it through open standards: SEP-24 for a user's own withdrawals, SEP-31 for business cross-border payments, and SEP-38 for quotes. A payout API does it behind one REST integration. The choice comes down to who owns the user, the KYC, and the corridors.

Stellar is unusual here. Most networks have no shared standard for off-ramps, so every provider invents its own. Stellar has a whole family of them. That's worth understanding even if you end up using an API, because the SEPs spell out the same steps every off-ramp has to solve.

Key takeaways

  • An anchor bridges Stellar assets and bank money, and talks to wallets through SEPs.
  • SEP-24 is interactive: the anchor hosts the KYC page, the wallet sends the payment with a memo.
  • SEP-31 is for businesses: a sending anchor pays a receiving anchor outside Stellar.
  • SEP-38 separates indicative prices from firm quotes with an expires_at. It's still a Draft.
  • Each anchor brings its own auth, KYC rules, and quote server, so corridors multiply integrations.
  • A payout API like BlindPay takes signed USDC on Stellar and pays out over local rails from one integration.

What is a Stellar anchor?

An anchor is a business that connects Stellar to the outside financial system. It accepts bank currency and delivers a Stellar asset, or accepts a Stellar asset and pays bank currency out. The SEP-24 spec describes its goal as "the standard way for anchors and wallets to interact on behalf of users" (SEP-24).

Anchors publish what they support in a stellar.toml file and authenticate clients with SEP-10 web authentication. On top of that sit the flows. Three matter for off-ramps: SEP-24, SEP-31, and SEP-38.

In payment terms, an anchor is an off-ramp with a public protocol. Types of crypto off-ramps places it next to exchanges, widgets, and payout APIs.

How does a SEP-24 withdrawal work?

SEP-24 is the hosted flow. The wallet asks, the anchor collects what it needs on its own page, and the wallet sends the funds.

  1. The wallet authenticates with SEP-10. The spec says anchors "must support SEP-10 and/or SEP-45 web authentication."
  2. The wallet starts a withdrawal. If the anchor needs KYC or bank details, it returns a URL, and the wallet "should open a popup browser window or embedded webview" to it.
  3. The user fills in the anchor's form. The transaction moves to pending_user_transfer_start.
  4. The wallet pays. "In order to fulfill a withdrawal, a wallet must make a payment to the Stellar address that the anchor provides," using the anchor's withdraw_memo.
  5. The anchor sees the payment and sends the bank transfer. Status ends at completed.

Good for a consumer wallet: the user picks a local anchor, and the anchor owns its compliance screen. The tradeoff is that you don't control that screen, and each anchor's form looks different.

How does SEP-31 move a cross-border payment?

SEP-31 is the business version. It "defines a protocol for enabling payments between two financial accounts that exist outside the Stellar network" (SEP-31). A sending anchor collects from its client and pays a receiving anchor, which delivers to the recipient's bank.

What the receiving anchor requires:

  • SEP-10 auth. "Sending Anchors must authenticate with Receiving Anchors via SEP-10 Web Authentication."
  • SEP-12 KYC, when the receiving anchor needs customer data, through its own KYC_SERVER.
  • SEP-38 quotes, for flows with asset conversion, through its ANCHOR_QUOTE_SERVER.

Transactions report statuses like pending_sender, pending_stellar, pending_receiver, pending_external, completed, refunded, expired, and error. SEP-31 is marked Active at version 3.1.0.

The catch is in the plural. Every receiving anchor is a separate counterparty with its own KYC fields and its own quote server. Three corridors can mean three integrations.

What do SEP-38 quotes lock?

SEP-38, the Anchor RFQ API, has two kinds of price (SEP-38):

  • Indicative, from GET /prices and GET /price. "These prices are indicative." The actual price is set at conversion time.
  • Firm, from POST /quote. The quoted amount "must be held in reserve" until expiry, and expires_at is "the date and time by which the anchor must receive funds from the client."

SEP-31 ties the two together: with a firm quote, "the Stellar transaction must be submitted to the Stellar network prior to the quote's expiration." Same idea as any binding payout quote. One more detail: SEP-38 is still a Draft, at version 2.5.0, so anchors may implement it differently.

That split mirrors the RFQ model in wholesale FX, covered in RFQ pricing for stablecoin FX.

How does a payout API do the same off-ramp?

One integration, one quote format, one KYC relationship. On BlindPay, a Stellar payout funded from your own wallet takes three calls (payout with Stellar):

  1. Quote. Create a payout quote against the recipient's bank account with a Stellar network. It locks the rate and fees for 5 minutes.
  2. Authorize and sign. Stellar has no allowance mechanism, so the authorize endpoint returns an unsigned transaction to BlindPay's treasury address. You sign it with your Stellar key and submit it.
  3. Create the payout. Send the quote ID and the signed transaction. BlindPay "independently re-validates the signed transaction against the quote (destination and amount)" before paying out.

On Stellar, BlindPay payouts are funded in USDC on mainnet, and development instances use USDB on stellar_testnet (supported chains). The fiat side runs on local rails: ACH, wire, RTP, and SWIFT (POBO/COBO) in the US and globally, Pix and TED in Brazil, SPEI in Mexico, ACH Colombia, Transfers 3.0 in Argentina, and SEPA in Europe. The recipient never sees Stellar. They see a bank deposit.

Which network to fund from in the first place is its own question; the best network to off-ramp stablecoins compares finality and fees.

How do anchors and a payout API compare?

SEP-24SEP-31SEP-38Payout API (BlindPay)
JobUser's own deposit or withdrawalBusiness cross-border paymentPrices and firm quotesBusiness payout to a bank account
Who runs KYCAnchor, on its hosted pageReceiving anchor, via SEP-12n/aBlindPay, through the API
PriceAnchor's termsSEP-38 quote, optionalIndicative or firm with expires_atLocked quote, 5 minutes
Integration per corridorOne per anchorOne per receiving anchorPer anchor quote serverOne API for every rail
Spec statusActive, v3.8.0Active, v3.1.0Draft, v2.5.0Versioned REST API

Illustrative example: what do three corridors cost to integrate?

Illustrative example. A company holding USDC on Stellar pays contractors in Brazil, Mexico, and the US every month. These counts describe integration work, not prices.

StepThrough anchors (SEP-31)Through a payout API
Find a counterparty per country3 receiving anchors1 provider
Auth setups (SEP-10 or API key)31
KYC field sets to map3 SEP-12 schemas1 customer schema
Quote formats to parseUp to 3 SEP-38 servers1 quote object
Status models to reconcile3 implementations of the SEP-31 statuses1 payout status model

The anchor column isn't wrong. It's open, and nobody sits in the middle. It's just more surface. Add a fourth country and the left column grows by one of everything.

Which one fits your product?

Pick by who owns the user.

  • Consumer Stellar wallet. SEP-24 fits. Users pick a local anchor, the anchor's page handles their KYC, and your wallet only sends the payment.
  • Remittance business with existing anchor partners. SEP-31 fits, if you already have the bilateral relationships in your corridors.
  • A business paying many recipients across countries. A payout API fits. One quote format, one KYC flow, and the same code path for Stellar and every other network you hold.

You can mix them. A wallet that offers SEP-24 to its users can still send its own treasury payouts through an API. And the hub question behind both, who earns what on a conversion, is in how on/off-ramp providers make money.

What to do next

If you hold USDC on Stellar, run one test payout on a development instance: create a quote with stellar_testnet and USDB, call authorize, sign, and create the payout. Time it end to end and compare it with the anchor flow you have today. The Stellar payout guide has the code.

FAQ