Skip to Content
DocumentationAuthentication

Authentication

Wakapay uses API keys and Bearer tokens to authenticate requests to the API. This guide explains how to securely authenticate your API calls.

Overview

Wakapay supports two authentication methods:

  1. API Key Authentication - Used to obtain access tokens
  2. Bearer Token Authentication - Used for all API requests
⚠️

Keep your credentials secure! Never commit API keys to version control or share them publicly. Treat them like passwords.

Step 1: Obtain an Access Token

Use your API credentials to obtain an access token:

Request

POST /business/auth Content-Type: application/json { "apiKey": "pk_test_****123", "apiSecret": "sk_test_****456" }

Token Request Example

curl -X POST https://api.test.wakapay.io/business/auth \ -H "Content-Type: application/json" \ -d '{ "apiKey": "pk_test_****123", "apiSecret": "sk_test_****456" }'

Response

{ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.****...****", "expiresIn": 3600 }

Step 2: Use the Access Token

Include the access token in the Authorization header of all API requests:

Authorization: Bearer YOUR_ACCESS_TOKEN

Authenticated Request Example

curl https://api.test.wakapay.io/business/balance \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Token Management

Token Expiration

Access tokens expire after 1 hour (3600 seconds). When a token expires, you’ll receive a 401 Unauthorized response:

{ "message": "token is malformed: token contains an invalid number of segments" }

Refresh Tokens

When your token expires, simply request a new one using your API credentials. There’s no separate refresh token mechanism.

Best Practices

  1. Cache tokens: Store tokens in memory and reuse them until they expire
  2. Handle expiration: Implement automatic token refresh when you receive a 401 error
  3. Don’t request unnecessarily: Request new tokens only when needed to avoid rate limits

Security Best Practices

Secure Storage

  • Environment variables: Store credentials in environment variables, not in code
  • Secret management: Use secret management services (AWS Secrets Manager, HashiCorp Vault)
  • Never log: Don’t log credentials or tokens in application logs
// Good const apiKey = process.env.WAKAPAY_API_KEY; // Bad const apiKey = "pk_test_****123";

API Key Types

Wakapay provides two types of API keys:

TypePrefixEnvironmentUse Case
Testyeuc...Test/SandboxDevelopment and testing
LiveCustomProductionReal transactions

Example Test API Key: yeuc****...****bbe3

Always use test keys during development. Switch to live keys only when you’re ready for production.

Authentication Errors

Invalid Credentials

{ "code": 0, "error": "invalid credentials" }

HTTP Status: 401

Causes:

  • Wrong apiKey
  • Wrong apiSecret
  • Credentials have been revoked

Missing Credentials

{ "code": 0, "error": "apiKey and apiSecret required" }

HTTP Status: 400

Causes:

  • Missing apiKey field
  • Missing apiSecret field
  • Empty apiKey or apiSecret

Missing Authorization Header

{ "message": "missing value in request header" }

HTTP Status: 401

Cause: No Authorization header in request

Malformed Token

{ "message": "token is malformed: token contains an invalid number of segments" }

HTTP Status: 401

Causes:

  • Invalid JWT format
  • Corrupted token
  • Expired token

Invalid Payload

{ "code": 0, "error": "invalid payload" }

HTTP Status: 400

Causes:

  • Malformed JSON in request body
  • Wrong Content-Type header (must be application/json)

Implementation Examples

Node.js

const axios = require("axios"); class WakapayClient { constructor(apiKey, apiSecret, environment = "test") { this.apiKey = apiKey; this.apiSecret = apiSecret; this.baseURL = environment === "production" ? "https://api.wakapay.io" : "https://api.test.wakapay.io"; this.token = null; this.tokenExpiry = null; } async authenticate() { const response = await axios.post(`${this.baseURL}/business/auth`, { apiKey: this.apiKey, apiSecret: this.apiSecret, }); this.token = response.data.data.accessToken; this.tokenExpiry = Date.now() + response.data.data.expiresIn * 1000; return this.token; } async getToken() { // Return cached token if still valid if (this.token && Date.now() < this.tokenExpiry - 60000) { return this.token; } // Otherwise, get a new token return await this.authenticate(); } async request(method, endpoint, data = null) { const token = await this.getToken(); const config = { method, url: `${this.baseURL}${endpoint}`, headers: { Authorization: "Bearer " + token, "Content-Type": "application/json", }, }; if (data) { config.data = data; } try { const response = await axios(config); return response.data; } catch (error) { if (error.response?.status === 401) { // Token expired, retry once with new token this.token = null; return await this.request(method, endpoint, data); } throw error; } } } // Usage const client = new WakapayClient( process.env.WAKAPAY_API_KEY, process.env.WAKAPAY_API_SECRET, "test", ); // Make authenticated requests const balance = await client.request("GET", "/business/balance");

Python

import os import time import requests from datetime import datetime, timedelta class WakapayClient: def __init__(self, api_key, api_secret, environment='test'): self.api_key = api_key self.api_secret = api_secret self.base_url = ( 'https://api.wakapay.io' if environment == 'production' else 'https://api.test.wakapay.io' ) self.token = None self.token_expiry = None def authenticate(self): response = requests.post( f'{self.base_url}/business/auth', json={ 'apiKey': self.api_key, 'apiSecret': self.api_secret } ) response.raise_for_status() data = response.json()['data'] self.token = data['accessToken'] self.token_expiry = datetime.now() + timedelta(seconds=data['expiresIn']) return self.token def get_token(self): # Return cached token if still valid (with 60s buffer) if self.token and datetime.now() < self.token_expiry - timedelta(seconds=60): return self.token # Otherwise, get a new token return self.authenticate() def request(self, method, endpoint, data=None): token = self.get_token() headers = { 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json' } url = f'{self.base_url}{endpoint}' try: if method == 'GET': response = requests.get(url, headers=headers) elif method == 'POST': response = requests.post(url, json=data, headers=headers) elif method == 'PUT': response = requests.put(url, json=data, headers=headers) elif method == 'DELETE': response = requests.delete(url, headers=headers) response.raise_for_status() return response.json() except requests.exceptions.HTTPError as e: if e.response.status_code == 401: # Token expired, retry once with new token self.token = None return self.request(method, endpoint, data) raise # Usage client = WakapayClient( os.getenv('WAKAPAY_API_KEY'), os.getenv('WAKAPAY_API_SECRET'), 'test' ) # Make authenticated requests balance = client.request('GET', '/business/balance')

Testing Authentication

Test your authentication implementation:

# 1. Get a token TOKEN=$(curl -s -X POST https://api.test.wakapay.io/business/auth \ -H "Content-Type: application/json" \ -d '{ "apiKey": "YOUR_API_KEY", "apiSecret": "YOUR_API_SECRET" }' | jq -r '.data.accessToken') # 2. Use the token curl https://api.test.wakapay.io/business/balance \ -H "Authorization: Bearer $TOKEN"

Next Steps

Now that you understand authentication, explore:

Last updated on