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.

OAuth 2.0Pro Pay · OUSDNo webhooks · poll

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.

Keys stay on the server. Client secrets (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/config

Returns authorization_endpoint, token_endpoint, userinfo_endpoint, balance_endpoint, charges_endpoint, and scopes_supported.

2

Create a Connect app

  1. Open Partner API portal (/partner-api)
  2. Create an app with name, website, logo, and exact-match OAuth callback URIs
  3. Copy opro_live_… (client id) and oprs_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=RANDOM

On 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