Core guides
Pro Connect · Auth & Pay
Third-party integrations on OpenPay Pro: OAuth sign-in (opro_live_ / oprat_), OUSD checkout charges, and developer app management — all native to Pro.
0
What Pro Connect is
OpenPay Pro Connect is the native integration layer for apps built on Pro — separate from the OpenPay Partner Transfer API on openpy.space.
OpenPay Pro Auth
Authorization-code OAuth. Users approve scopes on /pro/authorize; you exchange the code for an oprat_ access token.
OpenPay Pro Pay
Create a charge, redirect to /pro/checkout/{id}, user pays from OUSD balance. Poll until paid | canceled | expired.
oprs_live_…) never ship in VITE_ env or browser bundles. User tokens are oprat_… (Bearer).1
Discovery
Start from the public config document — endpoints, scopes, and checkout URL template:
GET https://openpaypro.space/api/public/pro/configReturns authorization_endpoint, token_endpoint, userinfo_endpoint, balance_endpoint, charges_endpoint, and scopes_supported.
2
Create a Connect app
- Open Partner API portal (
/partner-api) - Create an app with name, website, logo, and exact-match OAuth callback URIs
- Copy
opro_live_…(client id) andoprs_live_…(secret) once
Redirect URIs are compared after trimming trailing slashes — must match exactly. Same rule as OpenPay’s partner portal.
3
OAuth authorization code
Send the user to the consent screen:
https://openpaypro.space/pro/authorize?client_id=opro_live_…
&redirect_uri=https://your.app/callback
&scope=profile%20balance
&state=RANDOMOn Approve, Pro redirects to your redirect_uri with code, scope, and state. Exchange the code:
curl -X POST "https://openpaypro.space/api/public/pro/oauth/token" \
-H "Content-Type: application/json" \
-u "opro_live_…:oprs_live_…" \
-d '{
"grant_type": "authorization_code",
"code": "oprc_…",
"redirect_uri": "https://your.app/callback"
}'Response: access_token (oprat_…), expires_in, scope, user_id.
Scopes: profile · balance · payments
4
User profile & balance
# Profile (any valid token)
curl "https://openpaypro.space/api/public/pro/user/me" \
-H "Authorization: Bearer oprat_…"
# Balance (requires balance scope)
curl "https://openpaypro.space/api/public/pro/user/balance" \
-H "Authorization: Bearer oprat_…"5
Pro Pay charges
Authenticate with client id + secret (Basic or JSON body). Currency is always OUSD. Default TTL is 30 minutes (max 2 hours). No webhooks — poll until terminal status.
# Create
curl -X POST "https://openpaypro.space/api/public/pro/charges" \
-u "opro_live_…:oprs_live_…" \
-H "Content-Type: application/json" \
-d '{
"amount": 12.5,
"description": "Premium plan",
"reference": "ord_1001",
"success_url": "https://your.app/paid",
"cancel_url": "https://your.app/cancel"
}'
# Poll
curl "https://openpaypro.space/api/public/pro/charges/CHARGE_UUID" \
-u "opro_live_…:oprs_live_…"
# Cancel unpaid
curl -X POST "https://openpaypro.space/api/public/pro/charges/CHARGE_UUID/cancel" \
-u "opro_live_…:oprs_live_…"
# List
curl "https://openpaypro.space/api/public/pro/charges?status=paid" \
-u "opro_live_…:oprs_live_…"Create response includes checkout_url → redirect the payer there.
6
Checkout UX
Hosted page: https://openpaypro.space/pro/checkout/{charge_id}. Signed-in users see amount, merchant branding, balance, and Pay. Insufficient balance links to Top Up. After pay, Pro debits the payer and credits the app owner’s OUSD wallet (double-pay safe).
7
Copy-paste Node
const BASE = "https://openpaypro.space";
const CLIENT_ID = process.env.PRO_CLIENT_ID;
const CLIENT_SECRET = process.env.PRO_CLIENT_SECRET;
function basic() {
return "Basic " + Buffer.from(`${CLIENT_ID}:${CLIENT_SECRET}`).toString("base64");
}
export async function createCharge({ amount, reference, success_url, cancel_url }) {
const res = await fetch(`${BASE}/api/public/pro/charges`, {
method: "POST",
headers: {
Authorization: basic(),
"Content-Type": "application/json",
},
body: JSON.stringify({ amount, reference, success_url, cancel_url }),
});
if (!res.ok) throw new Error(await res.text());
return res.json(); // { id, checkout_url, status, expires_at, … }
}
export async function pollCharge(id, { intervalMs = 2000, timeoutMs = 120000 } = {}) {
const start = Date.now();
while (Date.now() - start < timeoutMs) {
const res = await fetch(`${BASE}/api/public/pro/charges/${id}`, {
headers: { Authorization: basic() },
});
const charge = await res.json();
if (["paid", "canceled", "expired"].includes(charge.status)) return charge;
await new Promise((r) => setTimeout(r, intervalMs));
}
throw new Error("charge_poll_timeout");
}8
Launch checklist
- Connect app created with production redirect URIs
- Client secret only on the server
- Authorize → token exchange → /user/me smoke test
- Charge create → checkout → poll to
paid - Cancel path tested for abandoned checkouts
- Users know they can revoke access under Developer → Connected apps