Skip to main content

Overview

This guide shows a common pairing:
  • Para for embedded / self-custody wallet UX and key management
  • Brale for regulated stablecoin issuance + on/off-ramps + orchestration
At a high level:
  1. Para provisions a wallet and gives you an onchain address
  2. You register that address with Brale as an Address (type=external)
  3. Brale returns an address_id
  4. Use that address_id as the destination (or source) in Brale Transfers
Para’s Brale walkthrough includes example Brale requests for convenience. For the latest Brale auth, required headers (like Idempotency-Key), and request body shapes, refer to Brale API Docs.

What is Para?

Para is an embedded wallet platform that helps fintech and payments teams ship self-custody wallets with a polished wallet UX and modern authentication (like passkeys), without forcing users into seed phrases or external wallet apps. Why teams choose Para (briefly):
  • Smooth onboarding: familiar sign-in flows with embedded wallet UX.
  • Self-custody security model: 2-of-2 MPC + passkeys and a defense-in-depth security architecture.
  • Flexible integration options: SDK-first (React and more) plus a REST API for server-side wallet + signing workflows.
  • User-friendly signing controls: permission prompts for transaction/message approvals (so you don’t have to build the entire approval UI).

Prerequisites

  • Para SDK integrated in your app (web/mobile/server) and you can access the user wallet address
  • Brale API credentials (client_id, client_secret)
  • You’ve chosen the chain(s) you want to support (examples below use EVM chains like base)

Step 1 — Authenticate with Brale

Exchange your Brale client credentials for a bearer token:
CLIENT_CREDENTIALS=$(
  printf "%s:%s" "${CLIENT_ID}" "${CLIENT_SECRET}" | base64 | tr -d '\n'
)

curl --request POST \
  --url https://auth.brale.xyz/oauth2/token \
  --header "Authorization: Basic ${CLIENT_CREDENTIALS}" \
  --header "Content-Type: application/x-www-form-urlencoded" \
  --data grant_type=client_credentials
Store the returned access_token and refresh it before it expires (expires_in).

Step 2 — Get your account_id

curl --request GET \
  --url https://api.brale.xyz/accounts \
  --header "Authorization: Bearer ${AUTH_TOKEN}"
If you operate managed accounts, select the correct account_id for the customer you’re funding.

Step 3 — Get the user’s wallet address from Para (minimal)

You only need one thing from Para to use Brale: the onchain address you want to fund.

Option A: Current selected wallet (React)

useWallet returns the wallet currently selected in the ParaModal.
import { useWallet } from "@getpara/react-sdk";

export default function CurrentWallet() {
  const { data: wallet } = useWallet();

  if (!wallet) return <div>No wallet connected</div>;

  return (
    <div>
      <p>Address: {wallet.address}</p>
      <p>Type: {wallet.scheme}</p>
      <p>ID: {wallet.id}</p>
    </div>
  );
}

Option B: All wallets (embedded + external) (React)

Use useAccount to access wallet information for both embedded and external types.
import { useAccount } from "@getpara/react-sdk";

export default function AllWallets() {
  const { embedded, external } = useAccount();

  const embeddedList = Object.values(embedded?.wallets ?? {});
  const externalList = Object.values(external?.wallets ?? {});

  return (
    <div>
      <h3>Embedded</h3>
      {embeddedList.map((w) => (
        <div key={w.id}>
          <p>
            {w.scheme}: {w.address}
          </p>
        </div>
      ))}

      <h3>External</h3>
      {externalList.map((w) => (
        <div key={w.id}>
          <p>
            {w.scheme}: {w.address}
          </p>
        </div>
      ))}
    </div>
  );
}
Not using React? Para supports other environments (REST API, server-side, React Native, etc.). Use Para’s docs as the source of truth for retrieving wallet data and for signing/broadcasting transactions.

Step 4 — Register the Para wallet in Brale (create an external Address)

Create an external address and capture the returned address_id.
curl --request POST \
  --url "https://api.brale.xyz/accounts/${ACCOUNT_ID}/addresses/external" \
  --header "Authorization: Bearer ${AUTH_TOKEN}" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: $(uuidgen)" \
  --data '{
    "name": "User Para Wallet (EVM)",
    "address": "0xE57e438aE0b1557bFC1ad70BD7751635E473D888",
    "transfer_types": ["base", "ethereum"]
  }'
Response:
{ "id": "2VcUIIsgARwVbEGlIYbhg6fGG57" }
That id is the Brale address_id you’ll use in Transfers.
If the same address format is valid across multiple networks (e.g., EVM chains), include all relevant onchain transfer_types. Otherwise, create separate external Addresses per chain/wallet type.

Step 5 — Fund the Para wallet via Brale Transfers

Option A: Wire → stablecoin → Para wallet

PARA_ADDRESS_ID="2VcUIIsgARwVbEGlIYbhg6fGG57"

curl --request POST \
  --url "https://api.brale.xyz/accounts/${ACCOUNT_ID}/transfers" \
  --header "Content-Type: application/json" \
  --header "Authorization: Bearer ${AUTH_TOKEN}" \
  --header "Idempotency-Key: $(uuidgen)" \
  --data '{
    "amount": { "value": "10", "currency": "USD" },
    "source": { "value_type": "USD", "transfer_type": "wire" },
    "destination": {
      "address_id": "'"${PARA_ADDRESS_ID}"'",
      "value_type": "SBC",
      "transfer_type": "base"
    }
  }'
Examples use SBC as a placeholder stablecoin. Replace it with the value type you intend to mint or pay out.

Option B: ach_debit → stablecoin → Para wallet

ach_debit flows require additional setup (end-user funding addresses, Plaid flows, etc.). Once configured, the Transfer pattern is the same: the destination is your Para address_id. See: ach_debit to end user wallet

Step 6 — Spending / sending from the Para wallet

Once funds land in the Para wallet, your app uses Para to sign and broadcast onchain transactions to send stablecoins onward. Brale does not custody the keys for external wallets.

Offramping (stablecoin → USD) with a self-custody wallet

To offramp to USD:
  1. Send stablecoins from the Para wallet to a Brale custodial deposit address (type=internal) for the customer’s Brale account.
  2. Use Brale’s stablecoin-to-fiat workflow to send USD to an external bank Address.
See: Stablecoin to Fiat (Offramp)

Troubleshooting

  • 401: refresh the Brale bearer token and retry POST requests with the same Idempotency-Key
  • 404 compatible_address_not_found: confirm:
    • you used the correct account_id
    • the destination address_id supports the transfer_type you’re using
  • Balance visibility:
    • Brale can return balances for custodial addresses (type=internal)
    • external wallets are outside Brale custody

References

Brale Para