Build · Integrate · Unlok

Connect your app to Unlok with OAuth2 or Personal Access Tokens. Trading, portfolio management, and more - all through a secure, production-ready API.

Overview

The Unlok API allows third-party vendors to build integrations that access user data with their explicit consent. We use OAuth 2.0 with PKCE (Proof Key for Code Exchange) to ensure secure authorization.

This guide walks you through the complete integration process:

  1. Submit your registration form to developers@unlok.com
  2. Receive your app credentials
  3. Implement the OAuth2 authorization flow
  4. Call APIs on behalf of users

1. Getting Started

To get started with the Unlok API, send us the details below via email to developers@unlok.com. Our team will review your submission and follow up with your credentials.

1

Company / Vendor Details

Include the following about your company:

  • Company Name - Your registered business name (e.g. Acme Trading Corp)
  • Company Website - Your company's website URL (e.g. https://acme-trading.com)
  • Business Email - A contact email for your team (e.g. dev@acme-trading.com)
  • Country - Your 2-letter country code (e.g. US, GB, SG)
  • Phone (optional) - A contact phone number
2

App Details

Tell us about the application you'd like to integrate:

  • App Name - A display name for your application (e.g. Trading Bot Pro)
  • Description (optional) - A short summary of what your app does
  • Logo URL - A publicly accessible URL to your app's logo
  • Homepage URL - Your app's public homepage
  • Support Email - Where users can reach your support team
  • Support URL (optional) - Link to your support/help center
  • Privacy Policy URL - Link to your privacy policy
  • Terms of Service URL - Link to your terms of service
  • Redirect URIs - One or more callback URLs where users will be redirected after authorization (e.g. https://acme-trading.com/callback)
  • Scopes Requested - The API permissions your app needs. You will only be able to request scopes that have been approved for your app. Available scopes:
    • read:accounts - Read account details and profile
    • write:accounts - Update account settings
    • read:orders - View orders and trade history
    • write:orders - Place and manage orders
    • read:banking - View banking and funding details
    • write:banking - Manage banking and funding
Environments: Unlok supports multiple app environments - DEV, UAT, and PROD. When your app is first provisioned, you will receive credentials for the DEV environment. Once you've completed testing, you can request promotion to UAT and then to PROD. Each environment has its own clientId and clientSecret, along with separate redirect URIs.
What happens next: Once we receive your details, our team will verify your submission and provision your app in the DEV environment. You will receive a clientId and clientSecret at your business email to get started with development and testing.

2. Authorization Flow (OAuth2 + PKCE)

Unlok uses the Authorization Code flow with PKCE. This is the most secure OAuth2 flow for user authorization.

┌──────────────┐      ┌──────────────┐      ┌──────────────┐
│   End User   │      │   Your App   │      │    Unlok     │
└──────┬───────┘      └──────┬───────┘      └──────┬───────┘
       │                     │                     │
       │  1. Click "Login    │                     │
       │     with Unlok"     │                     │
       │────────────────────▶│                     │
       │                     │                     │
       │                     │  2. Generate PKCE   │
       │                     │     code_verifier   │
       │                     │     code_challenge  │
       │                     │                     │
       │  3. Redirect to Unlok login page          │
       │◀────────────────────┼────────────────────▶│
       │                     │                     │
       │                     │     4. Show login   │
       │                     │        + consent    │
       │◀──────────────────────────────────────────│
       │                     │                     │
       │  5. User approves   │                     │
       │─────────────────────────────────────────▶ │
       │                     │                     │
       │  6. Redirect with ?code=xxx               │
       │◀──────────────────────────────────────────│
       │                     │                     │
       │                     │  7. POST /oauth/token
       │                     │     code + verifier │
       │                     │────────────────────▶│
       │                     │                     │
       │                     │  8. access_token    │
       │                     │     refresh_token   │
       │                     │◀────────────────────│
       │                     │                     │
       │  9. Access granted  │                     │
       │◀────────────────────│                     │
       │                     │                     │
                

Step-by-Step Implementation

1

Generate PKCE Challenge

Before redirecting the user, generate a PKCE code verifier and challenge:

// Generate random code_verifier (43-128 characters)
const codeVerifier = generateRandomString(64);

// Create code_challenge (SHA-256 hash, base64url encoded)
const codeChallenge = base64url(sha256(codeVerifier));

// Store codeVerifier securely (session/cookie) - you'll need it later
2

Redirect to Authorization

Build the authorization URL pointing to the Unlok login page and redirect the user. Include the scopes your app needs as a comma-separated list:

// The entry point is the Unlok login page - not the /oauth/authorize API directly.
// The login page handles authentication and then presents the consent screen.
const authUrl = new URL('https://join.unlok.com/en/login');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', 'your_client_id');
authUrl.searchParams.set('redirect_uri', 'https://yourapp.com/callback');
authUrl.searchParams.set('scopes', 'read:accounts,read:orders');  // comma-separated
authUrl.searchParams.set('state', generateRandomState());  // CSRF protection
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');

// Redirect the user's browser to Unlok
window.location.href = authUrl.toString();
3

Handle the Callback

After the user approves, Unlok redirects back to your redirect_uri with a code:

// Your callback URL receives:
// https://yourapp.com/callback?code=ulk_ac_xyz789&state=xyzABC123

// 1. Verify the state matches what you stored (CSRF protection)
// 2. Extract the code parameter
4

Exchange Code for Tokens

Call POST /oauth/token from your backend to exchange the code:

const response = await fetch('https://api.unlok.com/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'AUTH_CODE',
    code: 'ulk_ac_xyz789',
    redirect_uri: 'https://yourapp.com/callback',
    client_id: 'ulk_cid_abc123',
    client_secret: process.env.CLIENT_SECRET,
    code_verifier: storedCodeVerifier  // From step 1
  })
});

const { access_token, refresh_token, expires_in } = await response.json();

See the full API reference.

5

Make API Calls

Use the access token in the Authorization header. For example, fetch the authenticated user's profile from GET /oauth/userinfo (requires the read:accounts scope):

const response = await fetch('https://api.unlok.com/oauth/userinfo', {
  headers: {
    'Authorization': `Bearer ${access_token}`
  }
});

const { userId, email, firstName, lastName } = await response.json();
6

Refresh Tokens

When the access token expires, use the refresh token to get a new one:

const response = await fetch('https://api.unlok.com/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'REFRESH_TOKEN',
    refresh_token: storedRefreshToken,
    client_id: 'ulk_cid_abc123',
    client_secret: process.env.CLIENT_SECRET
  })
});

const { access_token, refresh_token } = await response.json();
// Store the new refresh_token - it replaces the old one
Token Lifetime:
  • Access tokens expire after 1 hour (3600 seconds)
  • Refresh tokens expire after 30 days
  • Refresh tokens are single-use - each refresh returns a new one

3. API Reference

For complete API documentation with request/response schemas, see the OpenAPI specification.

OAuth2 Endpoints

POST /oauth/token
POST /oauth/revoke
GET /oauth/authorize
GET /oauth/userinfo

Accounts Endpoints

GET /accounts
GET /accounts/{accountId}/positions
GET /accounts/{accountId}/position
GET /accounts/{accountId}/margin
GET /accounts/{accountId}/portfolios

Banking Endpoints

GET /banking/{accountId}/balance
GET /banking/{accountId}/balance/{ccy}
GET /banking/{accountId}/activity
GET /banking/{accountId}/txn-activity
POST /banking/deposit
POST /banking/withdraw
POST /banking/cancel-txn

Orders Endpoints

GET /oms/{accountId}/order/rules
GET /oms/{accountId}/orders
GET /oms/{accountId}/order/{orderId}
GET /oms/{accountId}/trades
POST /oms/what-if
POST /oms/order
DELETE /oms/order

Overview

Personal Access Tokens (PATs) provide a simple way to authenticate with the Unlok API for your own account. Unlike OAuth2, which is designed for third-party apps acting on behalf of users, PATs are meant for direct, personal use - scripts, automation, CLI tools, or programmatic access to your own data.

With a PAT you can:

  • Access the Unlok API without going through the OAuth2 authorization flow
  • Build personal scripts and automations against your account
  • Restrict access by IP address and read/write scope
  • Set a custom expiration date (up to 1 year)

1. Generate a Token

Navigate to app.unlok.com/developer and open the Personal Access Tokens section.

1

Configure Your Token

When creating a new token, you will need to provide the following:

  • Name - A descriptive label (e.g. "Trading Bot", "Portfolio Sync Script")
  • Expiration Date - When the token should expire. Must be between now and 1 year from today.
  • Access Scope - Choose between:
    • READ_WRITE - Full access (GET, POST, PUT, DELETE)
    • READ_ONLY - Read-only access (GET, HEAD, OPTIONS only)
  • IP Restrictions (optional) - A list of IP addresses that are allowed to use this token. If left empty, the token can be used from any IP.
2

Copy Your Token

After creation, you will be shown your token once. It will not be displayed again. Copy it and store it securely - you will use the entire token string to authenticate.

Important: Your token secret is hashed before storage. If you lose it, you cannot recover it - you will need to revoke the old token and generate a new one.

2. Authenticate with Your Token

To authenticate, call the POST /pat/login endpoint with your token. This exchanges your PAT for a short-lived session token (JWT) that you use for subsequent API requests.

1

Exchange PAT for Session Token

const response = await fetch('https://api.unlok.com/pat/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    token: 'your-tokenId.your-secret'
  })
});

const { userId, token } = await response.json();
// `token` is a JWT session token - use it for API calls
Why a two-step process? Your PAT is a long-lived secret. By exchanging it for a short-lived JWT, you limit exposure - the JWT expires quickly even if intercepted, while your PAT remains secure and is only transmitted once per session.

Example with cURL

curl -X POST https://api.unlok.com/pat/login \
  -H "Content-Type: application/json" \
  -d '{"token": "a1b2c3d4-e5f6-7890-abcd-ef1234567890.4f8c9a2b..."}'

Response:

{
  "userId": "usr_abc123",
  "token": "eyJhbGciOiJIUzI1NiIs..."
}

3. Make API Requests

Use the JWT returned from /pat/login in the Authorization header for all subsequent API calls:

curl https://api.unlok.com/accounts \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

JavaScript Example

const session = await fetch('https://api.unlok.com/pat/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ token: process.env.UNLOK_PAT })
}).then(r => r.json());

const accounts = await fetch('https://api.unlok.com/accounts', {
  headers: { 'Authorization': `Bearer ${session.token}` }
}).then(r => r.json());

Python Example

import os, requests

pat = os.environ["UNLOK_PAT"]

# Authenticate
session = requests.post("https://api.unlok.com/pat/login", json={"token": pat})
jwt_token = session.json()["token"]

# Make API calls
headers = {"Authorization": f"Bearer {jwt_token}"}
accounts = requests.get("https://api.unlok.com/accounts", headers=headers)
print(accounts.json())

4. API Reference

The only public endpoint for Personal Access Tokens is the login endpoint used to exchange your PAT for a session token. All other token management (create, list, revoke) is done through the Unlok dashboard at app.unlok.com/developer.

POST /pat/login

Exchange your Personal Access Token for a short-lived JWT session token.

5. Security Considerations

  • Treat your PAT like a password. Store it in environment variables or a secrets manager - never commit it to version control.
  • Use IP restrictions when possible. If your script only runs from a known server, restrict the token to that IP.
  • Prefer READ_ONLY scope unless your integration needs to create or modify data.
  • Set short expiration dates. A token that expires in 30 days is safer than one that expires in a year. You can always generate a new one.
  • Revoke unused tokens. Regularly review your active tokens and revoke any that are no longer needed.
  • Monitor login activity. Check /pat/login-activity periodically for unexpected access patterns.
If your token is compromised: Immediately revoke it from app.unlok.com/developer or by calling POST /pat/revoke with the token's ID. Revocation takes effect immediately and invalidates all active sessions created from that token.