OAuth2
client_credentials

OAuth2 authentication

The Partner Connect Hub API uses OAuth2 client_credentials. Exchange your client_id + client_secret for a short-lived access token, then send Authorization: Bearer <token> with every request.

Token endpoint
POST /oauth/token · Content-Type application/x-www-form-urlencoded · Tokens live for ~1h.
curl
curl -sS -X POST https://sunrift-hub.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=$CLIENT_ID" \
  -d "client_secret=$CLIENT_SECRET" \
  -d "scope=identity:read partners:*"

# Response
# {
#   "access_token": "eyJhbGciOi...",
#   "token_type": "Bearer",
#   "expires_in": 3600,
#   "scope": "identity:read partners:*"
# }
Available scopes
Request only what you need; minimal scope = least risk.
ScopeDescription
identity:readRead identity users
identity:writeCreate / update identity users
ledger:readRead accounting transactions
partners:*All partner integrations
Node.js example
Token + first order in one file. Use a token cache in production (re-fetch after expiry).
javascript
// Node 18+ (built-in fetch)
const TOKEN_URL = "https://sunrift-hub.com/oauth/token";

async function getToken() {
  const body = new URLSearchParams({
    grant_type: "client_credentials",
    client_id: process.env.CLIENT_ID,
    client_secret: process.env.CLIENT_SECRET,
    scope: "identity:read partners:*",
  });
  const res = await fetch(TOKEN_URL, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body,
  });
  if (!res.ok) throw new Error(`token: ${res.status}`);
  return (await res.json()).access_token;
}

async function placeOrder() {
  const token = await getToken();
  const res = await fetch("https://sunrift-hub.com/api/v1/orders", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${token}`,
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      sku_code: "partner_a.product_a.usd",
      amount: 25,
      external_order_id: "your-ref-123",
    }),
  });
  console.log(await res.json());
}
Python example
Same flow with requests.
python
import os, uuid, requests

TOKEN_URL = "https://sunrift-hub.com/oauth/token"

def get_token():
    r = requests.post(TOKEN_URL, data={
        "grant_type": "client_credentials",
        "client_id": os.environ["CLIENT_ID"],
        "client_secret": os.environ["CLIENT_SECRET"],
        "scope": "identity:read partners:*",
    }, timeout=10)
    r.raise_for_status()
    return r.json()["access_token"]

def place_order():
    token = get_token()
    r = requests.post(
        "https://sunrift-hub.com/api/v1/orders",
        headers={
            "Authorization": f"Bearer {token}",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json={
            "sku_code": "partner_a.product_a.usd",
            "amount": 25,
            "external_order_id": "your-ref-123",
        },
        timeout=20,
    )
    r.raise_for_status()
    print(r.json())
Best practices
  • Cache tokens until they expire — do not request a new one per call.
  • On 401, refresh the token once and retry.
  • On 429, respect the Retry-After header (exponential backoff).
  • Always send Idempotency-Key on POST /api/v1/orders (8–200 chars, unique per logical request).
  • Store client_secret only on backends; never embed it in mobile or browser code.
  • Rotate secrets periodically via your account manager.