Business-Level User Linking

Link players directly to a business instead of individual games. A business-linked user reference (obu_ prefix) is valid across every game and campaign under that business in the matching environment. This is the recommended approach for platforms managing multiple games under a single business entity.

This guide covers the Platform API flow for business-level linking. For game-level linking, see the Account Linking guide.

How it works

Loading diagram…

Authentication

All endpoints require a Platform API key with an active grant for the target business. Include these headers on every request:

HeaderRequiredDescription
AuthorizationYesBearer <platform_api_key>
X-Target-Business-IdYesThe business ID to operate against
X-Oncade-API-VersionYesv1
Idempotency-KeyConditionalRequired when email is not provided in the initiate call

Required scopes

ScopeEndpoints
business:users:link:createInitiate link
business:users:link:readLink details, list users, wallet balance, compliance check, campaign assign
business:users:link:removeRemove link

The obu_ user reference

Business user references encode the environment in their prefix:

PrefixEnvironmentExample
obu_Liveobu_a1b2c3d4-e5f6-7890-abcd-ef1234567890
obu_test_Testobu_test_a1b2c3d4-e5f6-7890-abcd-ef1234567890

These references are:

  • Unique per user per business per environment
  • Accepted by all platform API endpoints that take a userRef parameter
  • Valid across all games and campaigns under the business in the matching environment
  • Opaque and stable — derived from a one-way transform of the internal user ID

1. Initiate a link session

Create a pending link session and get a hosted URL for the player. Both email and metadata are optional. When email is omitted, the Idempotency-Key header is required and the player signs in or signs up during the hosted flow.

POST /api/v1/platform/business/users/link/initiate
curl -s -X POST \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "X-Target-Business-Id: $BUSINESS_ID" \
  -H "X-Oncade-API-Version: v1" \
  -H "Content-Type: application/json" \
  -d '{"email":"player@example.com"}' \
  https://oncade.gg/api/v1/platform/business/users/link/initiate

Response

// HTTP 201 Created (new session) or 200 OK (existing session)
{
  "url": "https://oncade.gg/link?session=session_a1b2c3d4e5f6...",
  "sessionKey": "session_a1b2c3d4e5f6..."
}

Returns 201 Created for new sessions (with Location header) or 200 OK if a session already exists for the same email or idempotency key.

2. Send the player to the hosted flow

  1. Store the sessionKey returned by the initiate call.
  2. Redirect or open a new window to the url provided in the response.
  3. The player signs in (or signs up) and approves the link on the hosted page.

3. Check link details

Poll the status of a link session. The userRef field appears once the player approves.

GET /api/v1/platform/business/users/link/details?session=<sessionKey>
curl -s \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "X-Target-Business-Id: $BUSINESS_ID" \
  -H "X-Oncade-API-Version: v1" \
  "https://oncade.gg/api/v1/platform/business/users/link/details?session=session_a1b2c3d4e5f6..."

Responses

{
  "businessId": "64b10b1cec13f995e9000001",
  "businessName": "Demo Studio",
  "prefilledEmail": "player@example.com",
  "status": "pending"
}

4. Handle webhook events

Business link webhooks are delivered to the platform's webhook endpoint (not individual game endpoints). Each payload includes businessId and the obu_-prefixed user_ref.

Events

EventWhen
User.Account.Link.StartedLink session created, player has not yet opened the flow
User.Account.Link.SucceededPlayer approved the link; user_ref is now available
User.Account.Link.FailedSomething prevented completion
User.Account.Link.CanceledPlayer backed out before finishing
User.Account.Link.RemovedLink was revoked (via API or dashboard)

Example payload

{
  "event": "User.Account.Link.Succeeded",
  "data": {
    "sessionKey": "session_a1b2c3d4e5f6...",
    "user_ref": "obu_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "businessId": "64b10b1cec13f995e9000001",
    "metadata": {
      "idempotencyKey": "biz-link-abc123",
      "platform_metadata": { "internal_id": "usr_123" }
    }
  }
}

The metadata object echoes back the Idempotency-Key header and any metadata you passed in the initiate call.

Webhook lifecycle

Loading diagram…

5. List linked users

Paginated list of all users linked to a business. Supports search by email or name.

GET /api/v1/platform/business/users?page=1&limit=20
# Paginated list
curl -s \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "X-Target-Business-Id: $BUSINESS_ID" \
  -H "X-Oncade-API-Version: v1" \
  "https://oncade.gg/api/v1/platform/business/users?page=1&limit=20"

# Search by email
curl -s \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "X-Target-Business-Id: $BUSINESS_ID" \
  -H "X-Oncade-API-Version: v1" \
  "https://oncade.gg/api/v1/platform/business/users?search=player@example.com"

Response

{
  "users": [
    {
      "linkId": "665a1b2c3d4e5f6a7b8c9d0e",
      "userRef": "obu_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "email": "player@example.com",
      "name": "Player One",
      "linkedAt": "2025-06-10T14:30:00.000Z",
      "environment": "live"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "totalCount": 1,
    "totalPages": 1,
    "hasNextPage": false,
    "hasPrevPage": false
  }
}

6. Get user wallet balance

Retrieve the wallet address and balance for a linked user.

GET /api/v1/platform/business/users/:userRef/wallet/balance
curl -s \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "X-Target-Business-Id: $BUSINESS_ID" \
  -H "X-Oncade-API-Version: v1" \
  "https://oncade.gg/api/v1/platform/business/users/obu_a1b2c3d4.../wallet/balance"

Response

{
  "address": "0x1234...abcd",
  "balance": "10.50"
}

7. Check compliance status

Before enabling features that require identity verification (e.g. payouts, withdrawals), check whether a linked user has completed KYC. If the status is not approved, redirect the user to the kycUrl to complete verification.

GET /api/v1/platform/business/users/:userRef/compliance
curl -s \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "X-Target-Business-Id: $BUSINESS_ID" \
  -H "X-Oncade-API-Version: v1" \
  "https://oncade.gg/api/v1/platform/business/users/obu_a1b2c3d4.../compliance"

Responses

{
  "userRef": "obu_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "status": "not_started",
  "kycUrl": "https://app.oncade.xyz/dashboard/profile"
}

Status values

StatusMeaning
not_startedUser has not begun identity verification
pendingVerification is in progress / under review
approvedUser is fully verified
rejectedVerification was rejected
action_requiredUser needs to provide additional information

The kycUrl field is included whenever status is not approved. Redirect the user to this URL to complete or retry verification.

8. Assign user to campaign

Assign a business-linked user to a platform-owned campaign. Creates a campaign link session automatically and returns a campaign-scoped userRef.

POST /api/v1/platform/business/users/:userRef/campaigns/:campaignId/assign
curl -s -X POST \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "X-Target-Business-Id: $BUSINESS_ID" \
  -H "X-Oncade-API-Version: v1" \
  "https://oncade.gg/api/v1/platform/business/users/obu_a1b2c3d4.../campaigns/camp_xyz/assign"

Response

// HTTP 201 Created (new assignment) or 200 OK (already assigned)
{
  "campaignUserRef": "c9d8e7f6-a1b2-4c3d-8e5f-6a7b8c9d0e1f",
  "email": "player@example.com",
  "assigned": true
}

9. Use obu_ refs in distributions

When creating a distribution, specify userRef instead of email for recipients. The platform resolves the obu_ reference to the linked user automatically. Recipients can mix userRef and email. Requires distribution:create scope.

POST /api/v1/platform/distributions
curl -s -X POST \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "X-Target-Business-Id: $BUSINESS_ID" \
  -H "X-Oncade-API-Version: v1" \
  -H "Idempotency-Key: dist-$(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "totalAmountCents": 5000,
    "mode": "fixed",
    "recipients": [
      { "userRef": "obu_a1b2c3d4...", "name": "Player One", "amount": 3000 },
      { "userRef": "obu_e5f6a7b8...", "name": "Player Two", "amount": 2000 }
    ],
    "memo": "Tournament payout"
  }' \
  "https://oncade.gg/api/v1/platform/distributions"

10. Remove a link

Unlink a user from the business by their obu_ reference.

POST /api/v1/platform/business/users/:userRef/link/remove
curl -s -X POST \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "X-Target-Business-Id: $BUSINESS_ID" \
  -H "X-Oncade-API-Version: v1" \
  "https://oncade.gg/api/v1/platform/business/users/obu_a1b2c3d4.../link/remove"

Response

{
  "success": true,
  "message": "Account link removed successfully"
}

Idempotency

The initiate endpoint supports two idempotency strategies:

  1. By email: If email is provided, a second call with the same email for the same business + environment returns the existing session (200 OK).
  2. By header: If email is omitted, the Idempotency-Key header is required. A second call with the same key returns the existing session.

Sessions expire after 24 hours if not approved.

Error codes

CodeHTTPDescription
BUSINESS_NOT_FOUND404Target business does not exist
INVALID_USER_REF400userRef does not start with obu_
USER_REF_NOT_FOUND404No user found for this reference in this business
LINK_NOT_FOUND404No active link found for this user
INVALID_EMAIL400Email format is invalid

End-to-end integration flow

Loading diagram…

Test checklist

  1. Use a test platform API key to produce obu_test_ references.
  2. Call POST /link/initiate with a test email.
  3. Complete the hosted flow at the returned URL.
  4. Confirm User.Account.Link.Succeeded webhook arrives with obu_test_ prefixed user_ref.
  5. Call GET /link/details?session=... to verify status: "approved" and userRef present.
  6. Call GET /users to see the linked user in the list.
  7. Call GET /users/:userRef/wallet/balance to verify wallet data.
  8. Call GET /users/:userRef/compliance to check KYC status. Verify kycUrl is present when status is not approved.
  9. Call POST /users/:userRef/campaigns/:campaignId/assign to test campaign assignment.
  10. Call POST /users/:userRef/link/remove and confirm User.Account.Link.Removed webhook.

Next steps