OAuth 2.0 API Reference

Authentication

OAuth 2.0 Authorization

Example Request:

GEThttps://whitebit.com/auth/login?clientId=YOUR_CLIENT_ID&state=SECURE_RANDOM_STATE

This endpoint initiates the OAuth 2.0 authorization flow for user authentication and obtaining an authorization code.

Parameters:

ParameterTypeRequiredDescription
clientIdstringYesYour application’s client ID
statestringRecommendedA 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:

ScopeDescription
generalGeneral API access
show.userinfoAccess to basic user information
users.readRead user data
users.email.readRead user email information
users.kyc.readInformation about whether a user has passed KYC verification
orders.readRead trading orders
orders.createCreate trading orders
orders.deleteDelete trading orders
balances.readRead account balances
markets.readRead market information
deals.readRead trading deals
orders_history.readRead order history
users.transactions.readRead user transactions
users.converts.readRead currency conversion history
users.balances.readRead user account balances
users.orders.readRead user orders
users.deals.readRead user deals

Get Access Token

POST/oauth2/token

This 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:

HeaderValue
Content-Typeapplication/x-www-form-urlencoded

Parameters:

ParameterTypeRequiredDescription
client_idstringYesYour application’s client ID
client_secretstringYesYour application’s client secret
codestringYesThe 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

POST/oauth2/refresh_token

This 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:

HeaderValue
Content-Typeapplication/x-www-form-urlencoded

Parameters:

ParameterTypeRequiredDescription
client_idstringYesYour application’s client ID
client_secretstringYesYour application’s client secret
tokenstringYesThe 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

POST/api/v4/accounts/transactions

This endpoint retrieves a paginated list of account transactions.

Request Headers:

HeaderValue
AuthorizationBearer YOUR_ACCESS_TOKEN
Content-Typeapplication/json

📖 View complete documentation


Get Currency Conversions

POST/api/v4/accounts/converts

This endpoint retrieves the history of currency conversions.

Request Headers:

HeaderValue
AuthorizationBearer YOUR_ACCESS_TOKEN
Content-Typeapplication/json

📖 View complete documentation


Get Orders History

POST/api/v4/accounts/orders

This endpoint retrieves the history of trading orders.

Request Headers:

HeaderValue
AuthorizationBearer YOUR_ACCESS_TOKEN
Content-Typeapplication/json

📖 View complete documentation


Get Executed Deals

POST/api/v4/accounts/deals

This endpoint retrieves the history of executed deals.

Request Headers:

HeaderValue
AuthorizationBearer YOUR_ACCESS_TOKEN
Content-Typeapplication/json

📖 View complete documentation


Get Main Account Balance

POST/api/v4/accounts/balances/main

This endpoint retrieves the main account balance information.

Request Headers:

HeaderValue
AuthorizationBearer YOUR_ACCESS_TOKEN
Content-Typeapplication/json

📖 View complete documentation


Get Spot Account Balance

POST/api/v4/accounts/balances/spot

This endpoint retrieves the spot trading account balance information.

Request Headers:

HeaderValue
AuthorizationBearer YOUR_ACCESS_TOKEN
Content-Typeapplication/json

📖 View complete documentation