Core guides

Connect, payments & Pro auth

Complete guide to Connect with OpenPay (OAuth 2.0), PayButton charges, partner payouts, OpenPay → Pro inbound top-up, and every OpenPay Pro wallet sign-in method.

Developer portal

Partner API · openpy.space

Create an app, copy Client ID + API key, set your domain for redirects, then ship Sign in, transfers, or PayButton.

Auth docs
API endpoint
  1. 1
    Register app
    Client ID + opk_ key
  2. 2
    Add domain
    Auto-fill callbacks
  3. 3
    Sign in / pay
    Auth · PayButton
  4. 4
    Go live
    Secrets on server

Portal

OpenPay Partner API portal

Use the official portal to register apps, manage keys, and follow the setup tutorial (Auth, Transfers, PayButton, Copy-paste, Reference).

Create app on openpy.space

AI tools

AI Partner Pack

Building with OpenAI, ChatGPT, Cursor, Lovable, Replit, or Claude? Paste the raw AI guide and OpenAPI into your agent — covers auth, pay, top-up, inbound, and ledger.

Merchants

Pro Pay · Merchant checkout

Third-party apps (and OpenPay) accept payment with OpenPay Pro methods. Charges settle to your OpenPay partner wallet; call inbound with pro_xfer: to credit a Pro @username / 0x.

A · Charges

POST /charges → PayButton → poll paid

B · Inbound

Credit merchant Pro @user / 0x after paid

C · Deep-link

/topup then /pay/@merchant

OpenPay QR

QR Pay · method openpay_pro

On OpenPay QR Pay / checkout, add method openpay_pro so merchants show a QR that pays via OpenPay Balance and credits an OpenPay Pro receive wallet.

Method id: openpay_pro
Label:     OpenPay Pro
Settle:    POST /charges → poll paid → POST inbound
Note:      pro_xfer:@shop:r_order_9001
Receive:   @username and/or 0x…

Top Up

OpenPay Pro payment methods

Same catalog as Pro Top Up → Pay with. Partners deep-link buyers to /topup — do not embed provider API keys in your app.
MethodLabelDescription
piPi Network (π)Pay with Pi · live π price → OUSD ($1) credited instantly
openpay_balanceOpenPay BalancePay from your connected OpenPay account · real debit
moonpayMoonPayCard / Apple Pay / Google Pay · MoonPay → OUSD
usdcUSDC PayPay with USDC · MoonPay Commerce → OUSD
helioCrypto DepositSOL / crypto · MoonPay Commerce → OUSD
solana_paySolana PayCommerce Kit · wallet connect, PaymentButton, Solana Pay QR → OUSD
circle_mintCircle DepositCircle Mint · USDC payin (payment intent + list payments) → OUSD
cash_payPay with CASHPhantom CASH (Solana SPL) · ledger balance or Solana Pay QR → OUSD 1:1
wallet_ousdWallet OUSDPay with your OpenPay Pro OUSD balance · buy any token
wallet_usdtWallet USDTPay with your OpenPay Pro USDT balance → OUSD 1:1
wallet_usdcWallet USDCPay with your OpenPay Pro USDC balance → OUSD 1:1
wallet_solWallet SOLPay with your OpenPay Pro SOL balance · live Solana price → OUSD
banxa_apple_payApple PayBanxa · Apple Pay (Face ID / Touch ID) → crypto settle → OUSD
banxa_google_payGoogle PayBanxa · Google Pay → crypto settle → OUSD
banxa_cardCardBanxa · debit / credit card → crypto settle → OUSD
banxa_bankBank TransferBanxa · bank transfer (ACH / SEPA / Faster Payments / PayID) → OUSD
onrampOnramp.moneyLocal bank rails (UPI / IMPS / SEPA / bank transfer) · onramp & offramp widget → OUSD
paymongoQR Ph & e-walletsPayMongo · GCash, Maya, GrabPay, banks · scan QR Ph → OUSD
paypalPayPalPayPal, Pay Later, Venmo or card · approve → OUSD
scan_payScan to payMulti-chain QR · SOL / USDC / USDT / CASH stables → verify TX → OUSD on OpenLedger
# Buyer funds with full Pro methods, then pays merchant
https://openpaypro.space/topup
https://openpaypro.space/pay/@shop?amount=250&asset=OUSD&note=order_9001

Exchanges

List OUSD on OpenPay Network

Exchanges integrate OUSD as a network asset: network id openpay, Partner Transfer for deposit / withdraw, Pro inbound for Pro wallets, Ledger for audit. OUSD is a ledger dollar (no public ERC-20 mint).

Step 1

Create a partner app

  1. Open Apps & keys → Register app.
  2. Copy the opk_live_… API key immediately (shown once). Save the Client ID (UUID).
  3. Enter only your domain (e.g. www.yourapp.com) and click Auto-fill & save for redirect URIs.
  4. Or register exact URIs manually, e.g. https://yourapp.com/openpay/callback
OPENPAY_CLIENT_ID="your-client-uuid"
OPENPAY_PARTNER_API_KEY="opk_live_..."
OPENPAY_PARTNER_API_BASE="https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api"
OPENPAY_REDIRECT_URI="https://yourapp.com/openpay/callback"

Never expose the partner API key in the browser — backend only.

Step 2

Connect with OpenPay

Authorization Code flow. Scopes: profile, balance. User lands on Authorize, signs in, Allow → your callback receives opc_….

Authorize URL

https://openpy.space/connect
  ?client_id=YOUR_CLIENT_ID
  &redirect_uri=https://yourapp.com/openpay/callback
  &scope=profile%20balance
  &state=RANDOM_CSRF_TOKEN

Drop-in Connect button

<a href="https://openpy.space/connect?client_id=YOUR_CLIENT_ID&redirect_uri=https://yourapp.com/openpay/callback&scope=profile%20balance&state=xyz"
   style="display:inline-flex;align-items:center;gap:8px;background:#1652f0;color:#fff;
   padding:12px 20px;border-radius:10px;font-weight:600;text-decoration:none;">
  Connect with OpenPay
</a>

Callback

# Success
https://yourapp.com/openpay/callback?code=opc_...&state=...

# Cancel
https://yourapp.com/openpay/callback?error=access_denied

# Verify state matches what you stored

Exchange code (server)

curl -X POST "https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/oauth/token" \
  -H "Content-Type: application/json" \
  -d '{
    "grant_type": "authorization_code",
    "code": "opc_...",
    "redirect_uri": "https://yourapp.com/openpay/callback",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "opk_live_YOUR_KEY"
  }'

User APIs (Bearer opa_live_…)

curl -H "Authorization: Bearer opa_live_..." https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/user/me
curl -H "Authorization: Bearer opa_live_..." https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/user/balance
# Typical /user/me response
{
  "user_id": "...",
  "account_number": "OP...",
  "full_name": "...",
  "username": "...",
  "avatar_url": "...",
  "balance": 12.34,
  "currency": "OUSD",
  "scope": "profile balance"
}
Codes expire in 10 minutes (single-use) · access tokens last 30 days

Step 3

OpenPay Pro — all sign-in methods

Exact setup for every method on /authpi. Full Markdown: /api/public/docs/openpay-auth · live page /docs/auth.

OpenPay

/authpi

OAuth 2.0 Connect — profile + balance scopes

API
GET/POST /api/public/openpay-auth
Callback
/auth/openpay/callback
Env
OPENPAY_OAUTH_CLIENT_ID · OPENPAY_PARTNER_API_KEY

Telegram

/authpi

Telegram Login OIDC + PKCE (oauth.telegram.org)

API
GET/POST /api/public/telegram-auth
Callback
/auth/telegram/callback
Env
TELEGRAM_CLIENT_ID · TELEGRAM_CLIENT_SECRET

Solana

/authpi

Sign In With Solana (Phantom / Wallet Standard)

API
GET/POST /api/public/solana-auth
Callback
—
Env
OPENPAY_AUTH_PASSWORD_SECRET (or SOLANA_…)

Pi Network

/authpi

Pi Browser SDK or Pi OAuth (external browser)

API
POST /api/public/pi-auth
Callback
/auth/pi/callback
Env
VITE_PI_CLIENT_ID

Phantom

/authpi

Extension · Google · Apple via Phantom Connect

API
Phantom SDK
Callback
/auth/callback
Env
VITE_PHANTOM_APP_ID (+ Portal allowlists)

WalletConnect

/authpi

EVM SIWE (personal_sign) → Supabase session

API
GET/POST /api/public/walletconnect-auth
Callback
—
Env
Auth secret · optional WCP Pay keys

MetaMask

/authpi

Embedded Wallets social OAuth (Web3Auth JWKS)

API
POST /api/public/web3auth-auth
Callback
Web3Auth modal / social chips
Env
VITE_WEB3AUTH_CLIENT_ID · WEB3AUTH_CLIENT_SECRET · JWKS

Shared server secrets

OPENPAY_AUTH_PASSWORD_SECRET="long-random-string"
SUPABASE_URL="https://YOUR_PROJECT.supabase.co"
SUPABASE_PUBLISHABLE_KEY="eyJ..."
SUPABASE_SERVICE_ROLE_KEY="eyJ..."   # server only — admin.createUser

MetaMask Embedded (Web3Auth)

VITE_WEB3AUTH_CLIENT_ID="your-client-id"
WEB3AUTH_CLIENT_ID="your-client-id"
WEB3AUTH_CLIENT_SECRET="your-secret"   # never VITE_
WEB3AUTH_JWKS_URL="https://api-auth.web3auth.io/.well-known/jwks.json"

Phantom Portal

VITE_PHANTOM_APP_ID="your-app-id"
# Allowlist each origin + /auth/callback in Phantom Portal

Client starters

import { startOpenPaySignIn } from "@/lib/openpay-auth"
import { startSolanaSignIn } from "@/lib/solana-auth"
import { startWalletConnectSignIn } from "@/lib/walletconnect-auth"
import { signInWithPi } from "@/lib/pi-network"

await startOpenPaySignIn({ redirectTo: "/dashboard" })
await startSolanaSignIn({ redirectTo: "/dashboard" })
await startWalletConnectSignIn({ redirectTo: "/dashboard" })
Security
  • Never expose opk_, wcp_, WEB3AUTH_CLIENT_SECRET, or service role in the browser
  • Verify OAuth state on every callback
  • Web3Auth: always check JWT aud = your Client ID
  • Verify Solana / SIWE signatures server-side before issuing credentials

Step 4

Accept OpenPay balance payments

Buyer pays from their OpenPay wallet. Funds credit your partner-app owner. Prefer PayButton /charges; use /pay/@username for hosted tag payments.

A · PayButton charge

curl -X POST "https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/charges" \
  -H "Authorization: Bearer opk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 19.99,
    "currency": "OUSD",
    "description": "Order #1234",
    "reference": "order_1234",
    "success_url": "https://yourapp.com/thanks",
    "cancel_url": "https://yourapp.com/cart"
  }'
# → { id, checkout_url, status, expires_at }  · TTL 2 hours
# → redirect buyer to checkout_url or https://openpy.space/paybutton/CHARGE_ID

Poll / cancel

# Status: created | paid | canceled | expired
curl -H "Authorization: Bearer opk_live_YOUR_KEY" \
  https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/charges/CHARGE_ID

curl -X POST -H "Authorization: Bearer opk_live_YOUR_KEY" \
  https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/charges/CHARGE_ID/cancel

# List
curl -H "Authorization: Bearer opk_live_YOUR_KEY" \
  "https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/charges?status=paid"

B · Hosted pay tag

https://openpy.space/pay/YOUR_USERNAME
  ?amount=25.00
  &currency=OUSD
  &note=order_1234
  &success_url=https://yourapp.com/thanks
  &cancel_url=https://yourapp.com/cart

# Success return: ?openpay_return=1&openpay_ref=order_1234&openpay_tx=...
# Cancel return:  ?openpay_cancel=1

Pay flow

  1. Open pay link → amount + note
  2. Pay → balance check → debit OUSD → thank-you
  3. Redirect to your success_url
  4. Backend verifies paid, then fulfills

Step 5

Payouts — Partner transfers

Debits the key owner’s OpenPay balance and credits the recipient. Always send Idempotency-Key. Prefer OP… account numbers over @username.
# Resolve account
curl -H "Authorization: Bearer opk_live_YOUR_KEY" \
  https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/accounts/@satoshi

# Send payout
curl -X POST "https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/transfers" \
  -H "Authorization: Bearer opk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"to":"OP...","amount":10.00,"note":"Payout"}'

# Partner treasury
curl -H "Authorization: Bearer opk_live_YOUR_KEY" https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/me
curl -H "Authorization: Bearer opk_live_YOUR_KEY" https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/balance

Step 6

OpenPay → OpenPay Pro (inbound / top-up)

Credit a Pro wallet after an OpenPay payment using note routing + inbound API.

Note: pro_xfer:@alice:r_ref or pro_xfer:0x…:r_ref

curl -X POST "https://openpaypro.space/api/public/openpay/inbound" \
  -H "Authorization: Bearer opk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "@alice",
    "amount": 25,
    "openpay_tx_id": "UNIQUE_TX_ID",
    "note": "pro_xfer:@alice:r_1",
    "from_username": "bob"
  }'

Idempotent on openpay_tx_id. Pro users can also Receive → Create OpenPay receive link. Product deep-link: /topup.

Inbound markdown

Step 7

Minimal Node example

const API = process.env.OPENPAY_PARTNER_API_BASE || "https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api";
const KEY = process.env.OPENPAY_PARTNER_API_KEY; // opk_live_…
const CLIENT_ID = process.env.OPENPAY_CLIENT_ID;
const REDIRECT = process.env.OPENPAY_REDIRECT_URI;

export function connectUrl(state) {
  const u = new URL("https://openpy.space/connect");
  u.searchParams.set("client_id", CLIENT_ID);
  u.searchParams.set("redirect_uri", REDIRECT);
  u.searchParams.set("scope", "profile balance");
  u.searchParams.set("state", state);
  return u.toString();
}

export async function exchangeCode(code) {
  const res = await fetch(`${API}/oauth/token`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      grant_type: "authorization_code",
      code,
      redirect_uri: REDIRECT,
      client_id: CLIENT_ID,
      client_secret: KEY,
    }),
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json(); // { access_token: "opa_live_...", ... }
}

export async function createCharge({ amount, reference, success_url, cancel_url }) {
  const res = await fetch(`${API}/charges`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      amount,
      currency: "OUSD",
      description: reference,
      reference,
      success_url,
      cancel_url,
    }),
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json(); // { id, checkout_url, ... }
}

export async function transfer({ to, amount, note, idempotencyKey }) {
  const res = await fetch(`${API}/transfers`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": idempotencyKey,
    },
    body: JSON.stringify({ to, amount, note }),
  });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
}

Step 8

API cheat sheet

MethodPathAuth
GET/meopk_
GET/balanceopk_
GET/accounts/:idopk_
POST/transfersopk_ + Idempotency-Key
GET/transfersopk_
POST/chargesopk_
GET/charges/:idopk_
GET/charges?status=opk_
POST/charges/:id/cancelopk_
POST/oauth/tokenbody client_secret
GET/user/meopa_
GET/user/balanceopa_
POST/api/public/openpay/inboundopk_ / opdk_ (Pro)

Base: https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api
Full reference: /docs/api · OpenAPI: /api/public/docs/openapi

Step 9

Public Ledger API

Append-only public ledger of OpenPay Pro transactions. Auth with x-api-key or Authorization: Bearer.

GET https://openpaypro.space/api/public/ledger/entries?limit=50&asset=OUSD&type=buy
x-api-key: YOUR_LEDGER_KEY

Types: send · receive · buy · sell · swap · mint · reward. Docs: /docs/ledger.

Step 10

WalletConnect Pay

Pro can pay WalletConnect Pay merchant links from the in-app scanner (/scan → /wc-pay).

  • Merchant creates a WC Pay link via WalletConnect Pay Merchant API
  • User scans QR or opens the link in Pro
  • Requires server env WALLETCONNECT_PAY_API_KEY

This is a payer integration inside Pro — not a partner webhook.

Step 11

Charges polling (no partner webhooks)

Confirm payments by polling GET /charges/:id. There is no partner-facing payment webhook today.

GET https://araojncyittkahvvpdrn.supabase.co/functions/v1/partner-transfer-api/charges/CHARGE_ID
Authorization: Bearer opk_live_YOUR_KEY

# Fulfill only when status === "paid"

Internal webhooks (MoonPay, KYC, Circle) power Pro itself and are not exposed to third-party apps.

Step 12

OpenNFT mint (high level)

Pro users mint collectibles on OpenPay OpenNFT via a connected OpenPay account (Settings → Connect OpenPay). Marketplace: openpy.space/web3/nft.

  • User must link OpenPay OAuth in Pro first
  • Mint calls OpenPay partner NFT APIs server-side
  • Ledger type mint is recorded on the Pro Ledger API

Step 13

Errors & launch checklist

401 / invalid_client — bad or quoted opk_live_… / wrong client_id

redirect_uri not registered — must match allowlist exactly

403 — origin not whitelisted

400 — validation, insufficient balance

Scopes — Connect uses profile and balance

  • ✓Partner app + secrets on server only (openpy.space/partner-api)
  • ✓Redirect URIs registered (exact match)
  • ✓Connect → token → store opa_live_ server-side
  • ✓Charges or /pay/@tag with success/cancel URLs
  • ✓Poll until paid; transfers use Idempotency-Key
  • ✓Inbound (if used) unique openpay_tx_id + pro_xfer note
Errors & retries reference

FAQ

OpenPay Pro FAQ

How do I connect OpenPay to Pro?

Settings → Connected → Connect OpenPay (OAuth). You can then send/receive via OpenPay balance and mint OpenNFTs.

Where do trade fees go?

Platform fees credit the admin fee wallet — typically @openpay.

Where do merchants receive Pro earnings?

Use /docs/pro-pay — charges → inbound with pro_xfer: to @username / 0x. QR Pay method: openpay_pro.

Is there a partner webhook?

Not yet — poll GET /charges/:id after payment return.

Full FAQ