Documentation Index
Fetch the complete documentation index at: https://docs.portalhq.io/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Meld’s White-Label API is an iframe-based experience for buy, sell, and transfer crypto sessions powered by an aggregated network of providers. Portal exposes thin proxy endpoints under/clients/me/integrations/meld/*.
The minimum end-to-end sequence is:
- Discover supported countries, currencies, and payment methods.
- Quote the conversion to confirm pricing and pick a service provider.
- Create a widget session — Meld returns a
widgetUrlyou embed in an iframe or load via redirect. - Track transaction status by session or transaction ID (or via Meld webhooks configured in Meld Dashboard).
Prerequisites
- The Meld integration is enabled for the target Portal environment. See Meld integration overview.
- You hold a valid Portal Client API session token. See the Client API quickstart.
https://api.portalhq.io. For sandbox/dev Portal environments, swap the host accordingly.
Step 1: Discovery
Call the discovery endpoints to populate dropdowns and validate selections before opening the widget. All discovery endpoints areGET and require no request body.
Countries
Fiat currencies
Crypto currencies
Meld doesn’t accept a separate chain parameter — each token has a distinct
currencyCode per chain (a “Meld Code”). See Meld’s cryptocurrency coverage for the full list.Payment methods
GET /discovery/service-providers— available providers and their categories/logos.GET /discovery/defaults— default fiat currency and payment methods per country.GET /discovery/buy-limits,GET /discovery/sell-limits— min/max/default amounts.GET /discovery/kyc-limits— daily/weekly/monthly limits per KYC tier.
Step 2: Get a quote
CallPOST /retail/quote to fetch live pricing across providers before opening the widget. The response includes one MeldQuote per available provider, sorted by Meld’s recommendation logic.
| Field | Type | Required | Description |
|---|---|---|---|
countryCode | string | Yes | ISO-3166-1 alpha-2 country code (for example US). |
sourceCurrencyCode | string | Yes | Source currency (fiat for buy, crypto for sell). |
destinationCurrencyCode | string | Yes | Destination currency. |
sourceAmount | number | Yes | Amount of source currency to convert. |
walletAddress | string | No | Destination wallet address (informs provider eligibility). |
paymentMethodType | string | No | Filter to a specific payment method (for example CREDIT_DEBIT_CARD). |
serviceProviders | string[] | No | Restrict the quote to specific providers. |
subdivision | string | No | State/region code, when required by the country. |
Whichever side carries crypto —
destinationCurrencyCode on a buy, sourceCurrencyCode on a sell, or both on a transfer — uses a Meld Code that selects both the asset and the chain. Pass the same code into the widget session in Step 3 so the quoted price matches the actual settlement chain.serviceProvider from the response — you’ll pass it into the widget session in the next step.
Step 3: Create a widget session
CallPOST /retail/widget with the chosen serviceProvider and the same currency/amount fields used for quoting. Meld returns a widgetUrl you embed in an iframe (or load via redirect).
| Field | Type | Required | Description |
|---|---|---|---|
sessionType | "BUY" | "SELL" | "TRANSFER" | Yes | The flow direction. |
sessionData.countryCode | string | Yes | ISO-3166-1 alpha-2 country code. |
sessionData.sourceAmount | string | Yes | Source amount (string-encoded decimal). |
sessionData.sourceCurrencyCode | string | Yes | Source currency. |
sessionData.destinationCurrencyCode | string | Yes | Destination currency. |
sessionData.serviceProvider | string | Yes | Provider chosen from the quote response. |
sessionData.walletAddress | string | No | Destination wallet address. Pre-fills the widget. |
sessionData.walletTag | string | No | Memo / destination tag for chains that require it. |
sessionData.paymentMethodType | string | No | Pre-selects the payment method. |
sessionData.lockFields | string[] | No | Field names the user cannot modify (for example ["walletAddress"]). See Meld’s docs. |
sessionData.redirectUrl | string | No | URL Meld redirects to when the user finishes the flow. |
externalSessionId | string | No | Your reference for this session (recorded on Meld’s transaction). |
customerId | string | No | Meld customerId if you have pre-created a customer. |
bypassKyc | boolean | No | Skip KYC where allowed by the provider/jurisdiction. Use cautiously. |
Step 4: Track transaction status
The widget drives the user through payment, KYC (when required), and settlement. To inspect the resulting transaction from your backend, look it up by widget session ID:Prefer Meld webhooks over polling for transaction lifecycle updates. Configure them in Meld Dashboard — see Webhooks.
Optional: Pre-create a Meld customer
The widget collects user identity inside the iframe, so you do not need a pre-existing Meld customer record to launch a session. Pre-creating one is useful when you want to:- Pre-fill identifying fields to speed up KYC
- Track Meld history for a Portal client outside of widget sessions
- Associate multiple sessions with a persistent Meld customer record
POST /customers once per Portal client. Portal derives an identifier from your custodian + environment + client identity, so you don’t pass it yourself. Meld returns this value as externalId on customer objects and as externalCustomerId on quote, widget session, and transaction objects — both fields hold the same value.
All body fields are optional, but providing identifying data up front helps Meld’s KYC providers complete checks faster. Required fields vary by service provider and country — query
GET /discovery/kyc-limits to understand tier requirements.409 Conflict with the existing customer ID at details.meldCustomerId on the error envelope. Retrieve the full record with GET /customers:
GET /customers returns a list-shaped response under data.customers. If a customer exists for the current Portal client, pass data.customers[0].id as customerId on POST /retail/widget (Step 3) to associate the widget session with that Meld customer record. If data.customers is empty, there is no existing customer to reuse — omit customerId or create one first with POST /customers.
Sandbox testing
Meld provides separate API keys, base URLs, and test data for sandbox. Configure your Portal Development environment with a sandbox Meld API key, then run the BUY happy path:- Country:
US - Source:
USD100 - Destination:
USDC - Service provider: any returned by
/retail/quote
Error handling
Portal forwards Meld’s HTTP status codes (4xx / 5xx) and preserves the upstream error message where possible. The full Meld error envelope is documented at docs.meld.io/reference. Portal-side errors you may see:400 Meld integration is not enabled— turn on the Meld integration for the current Portal environment in the Portal Dashboard.400 Meld API key is not configured for this environment— paste a valid Meld API key into the integration config.409 Conflict(onPOST /customers) — a Meld customer already exists for this Portal client. UseGET /customersinstead.
Next steps
Meld API Reference
Browse every Meld endpoint Portal exposes.
Webhooks
Configure Meld webhooks in Meld Dashboard for transaction lifecycle updates.