OAuth 2.0 API Reference
Authentication
OAuth 2.0 Authorization
Example Request:
https://whitebit.com/auth/login?clientId=YOUR_CLIENT_ID&state=SECURE_RANDOM_STATEThis endpoint initiates the OAuth 2.0 authorization flow for user authentication and obtaining an authorization code.
Parameters:
| Parameter | Type | Required | Description | 
|---|---|---|---|
clientId | string | Yes | Your application’s client ID | 
state | string | Recommended | A secure random string used to maintain state between the request and callback and prevent CSRF attacks | 
Using the State Parameter (Best Practice)
The state parameter is crucial for security in OAuth flows:
import crypto from 'crypto';
import http from 'http';
import https from 'https';
import { URL, URLSearchParams } from 'url';
import { parse as parseUrl } from 'url';
import { parse as parseQueryString } from 'querystring';
 
// Simple in-memory session store (for production use a proper store)
const sessions = new Map<string, Record<string, any>>();
 
// Generate a secure random state value
function generateSecureState(): string {
  return crypto.randomBytes(32)
    .toString('base64')
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}
 
// Generate session ID
function generateSessionId(): string {
  return crypto.randomBytes(16).toString('hex');
}
 
// Create HTTP server
const server = http.createServer((req, res) => {
  // Get or create session
  let sessionId = '';
  const cookies = req.headers.cookie?.split(';').map(c => c.trim());
  const sessionCookie = cookies?.find(c => c.startsWith('sessionId='));
 
  if (sessionCookie) {
    sessionId = sessionCookie.split('=')[1];
    if (!sessions.has(sessionId)) {
      sessionId = '';
    }
  }
 
  if (!sessionId) {
    sessionId = generateSessionId();
    res.setHeader('Set-Cookie', `sessionId=${sessionId}; HttpOnly; Path=/; Max-Age=600`);
    sessions.set(sessionId, {});
  }
 
  const session = sessions.get(sessionId) || {};
 
  // Parse URL and path
  const parsedUrl = parseUrl(req.url || '');
  const pathname = parsedUrl.pathname || '';
 
  // Handle routes
  if (pathname === '/auth/login') {
    // Initiate OAuth flow
    const state = generateSecureState();
    session.oauth_state = state;
 
    res.writeHead(302, {
      'Location': `https://whitebit.com/auth/login?clientId=YOUR_CLIENT_ID&state=${state}`
    });
    res.end();
  }
  else if (pathname === '/auth/callback') {
    // Handle OAuth callback
    const query = parseQueryString(parsedUrl.query || '');
    const receivedState = query.state as string;
    const storedState = session.oauth_state;
 
    // Clear the stored state immediately
    delete session.oauth_state;
 
    // Verify the state parameter
    if (!receivedState || receivedState !== storedState) {
      res.writeHead(400);
      res.end('State validation failed');
      return;
    }
 
    // State is valid, proceed with code exchange
    const code = query.code as string;
    if (code) {
      // Exchange code for token
      exchangeCodeForToken(code, sessionId, res);
    } else {
      res.writeHead(400);
      res.end('Missing authorization code');
    }
  }
  else {
    // Handle other routes or 404
    res.writeHead(404);
    res.end('Not found');
  }
});
 
// Exchange the authorization code for access token
function exchangeCodeForToken(
  code: string,
  sessionId: string,
  res: http.ServerResponse
): void {
  const params = new URLSearchParams({
    client_id: 'YOUR_CLIENT_ID',
    client_secret: 'YOUR_CLIENT_SECRET',
    code: code
  }).toString();
 
  const options = {
    hostname: 'whitebit.com',
    port: 443,
    path: '/oauth2/token',
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': Buffer.byteLength(params)
    }
  };
 
  const request = https.request(options, (tokenRes) => {
    let data = '';
 
    tokenRes.on('data', (chunk) => {
      data += chunk;
    });
 
    tokenRes.on('end', () => {
      try {
        const tokenData = JSON.parse(data);
 
        // Store tokens in session
        const session = sessions.get(sessionId);
        if (session) {
          session.access_token = tokenData.data.access_token;
          session.refresh_token = tokenData.data.refresh_token;
        }
 
        // Redirect to dashboard
        res.writeHead(302, {
          'Location': '/dashboard'
        });
        res.end();
      } catch (error) {
        console.error('Failed to parse token response:', error);
        res.writeHead(500);
        res.end('Authentication failed');
      }
    });
  });
 
  request.on('error', (error) => {
    console.error('Token exchange failed:', error);
    res.writeHead(500);
    res.end('Authentication failed');
  });
 
  // Write data to request body
  request.write(params);
  request.end();
}
 
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});This approach protects users from cross-site request forgery attacks and ensures the authorization response was intended for your application.
Note: OAuth scopes are predefined during client application setup and cannot be modified during the authorization request. The access token will include all scopes that were approved during client creation.
Available Scopes
The following scopes can be requested during client setup:
| Scope | Description | 
|---|---|
general | General API access | 
show.userinfo | Access to basic user information | 
users.read | Read user data | 
users.email.read | Read user email information | 
users.kyc.read | Information about whether a user has passed KYC verification | 
orders.read | Read trading orders | 
orders.create | Create trading orders | 
orders.delete | Delete trading orders | 
balances.read | Read account balances | 
markets.read | Read market information | 
deals.read | Read trading deals | 
orders_history.read | Read order history | 
users.transactions.read | Read user transactions | 
users.converts.read | Read currency conversion history | 
users.balances.read | Read user account balances | 
users.orders.read | Read user orders | 
users.deals.read | Read user deals | 
Get Access Token
/oauth2/tokenThis endpoint activates an access token by exchanging an authorization code.
❗ Important Notes:
- Access token duration is 300 seconds
 - The IP of the client must be added to WB Allowlist
 
Request Headers:
| Header | Value | 
|---|---|
Content-Type | application/x-www-form-urlencoded | 
Parameters:
| Parameter | Type | Required | Description | 
|---|---|---|---|
client_id | string | Yes | Your application’s client ID | 
client_secret | string | Yes | Your application’s client secret | 
code | string | Yes | The authorization code received from the authorization endpoint | 
Response:
{
  "data": {
    "access_token": "MZM1MDBMMJYTNWM4MI0ZNTIYLTKXNDATNZY1MZHKM2Y2MJY3",
    "expires_in": 300,
    "refresh_token": "ODK5ZTVKZDUTYTI5ZC01NWJHLTGZZDMTYWFKYTNMNJHHMGZM",
    "scope": "codes.apply,show.userinfo",
    "token_type": "Bearer"
  }
}Error Responses:
Status 401 - Not authorized:
{
  "data": {
    "message": ["Invalid request"]
  }
}Status 422 - Validation errors:
{
  "errors": {
    "client_id": ["validation.required"],
    "client_secret": ["validation.required"],
    "code": ["validation.required"]
  },
  "notification": null
}Refresh Token
/oauth2/refresh_tokenThis endpoint creates a new access token using a refresh token.
❗ Important Notes:
- Refresh token duration is 600 seconds
 - Rate limit: 1 request per second
 - The IP of the client must be added to WB Allowlist
 
Request Headers:
| Header | Value | 
|---|---|
Content-Type | application/x-www-form-urlencoded | 
Parameters:
| Parameter | Type | Required | Description | 
|---|---|---|---|
client_id | string | Yes | Your application’s client ID | 
client_secret | string | Yes | Your application’s client secret | 
token | string | Yes | The refresh token received from the token endpoint | 
Response:
{
  "data": {
    "access_token": "NTBLZJKYNZETNJFIZC0ZNGM1LWJMYTMTODBJYZRKNWE2NMRM",
    "expires_in": 300,
    "refresh_token": "ODZMNMRHM2ETMZQZZI01OTQYLWEWMZATNWQ0NDYZNJBMOWUW",
    "scope": "codes.apply,show.userinfo",
    "token_type": "Bearer"
  }
}Error Response:
{
  "data": {
    "token": ["Invalid token."]
  }
}Account Endpoints
Get Account Transactions
/api/v4/accounts/transactionsThis endpoint retrieves a paginated list of account transactions.
Request Headers:
| Header | Value | 
|---|---|
Authorization | Bearer YOUR_ACCESS_TOKEN | 
Content-Type | application/json | 
Get Currency Conversions
/api/v4/accounts/convertsThis endpoint retrieves the history of currency conversions.
Request Headers:
| Header | Value | 
|---|---|
Authorization | Bearer YOUR_ACCESS_TOKEN | 
Content-Type | application/json | 
Get Orders History
/api/v4/accounts/ordersThis endpoint retrieves the history of trading orders.
Request Headers:
| Header | Value | 
|---|---|
Authorization | Bearer YOUR_ACCESS_TOKEN | 
Content-Type | application/json | 
Get Executed Deals
/api/v4/accounts/dealsThis endpoint retrieves the history of executed deals.
Request Headers:
| Header | Value | 
|---|---|
Authorization | Bearer YOUR_ACCESS_TOKEN | 
Content-Type | application/json | 
Get Main Account Balance
/api/v4/accounts/balances/mainThis endpoint retrieves the main account balance information.
Request Headers:
| Header | Value | 
|---|---|
Authorization | Bearer YOUR_ACCESS_TOKEN | 
Content-Type | application/json | 
Get Spot Account Balance
/api/v4/accounts/balances/spotThis endpoint retrieves the spot trading account balance information.
Request Headers:
| Header | Value | 
|---|---|
Authorization | Bearer YOUR_ACCESS_TOKEN | 
Content-Type | application/json |