Authentication

Overview

The Kira API uses token-based authentication. You'll need to authenticate with your Client ID, Password, and API Key to receive an access token for all subsequent API calls.

Prerequisites

You need the following credentials provided by Kira:

  • Client ID - UUID that identifies your application
  • Password - Secret password for authentication
  • API Key - API key for request validation

⚠️ Important: Keep your password and API key secure. Never commit them to version control or expose them in client-side code.

Authenticate

Endpoint

POST /auth

Headers

HeaderRequiredDescription
Content-TypeYesMust be application/json
x-api-keyYesYour API key provided by Kira

Request Body

{
  "client_id": "your-client-id-uuid",
  "password": "your-password"
}

Example Request

curl --location 'https://api.balampay.com/auth' \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: YOUR_API_KEY' \
  --data '{
    "client_id": "b7b3f66c-7e19-4235-bf13-bcb8a6189082",
    "password": "your-password"
  }'

Response

{
  "message": "Auth token",
  "data": {
    "access_token": "eyJraWQiOiJHdVlJZDVoUlM2ajJUVG9RekpKN1VPc3FoNmUxdWxsT2NkSG9COUZGUlB3PSIsImFsZyI6IlJTMjU2In0...",
    "expires_in": 3600,
    "token_type": "Bearer"
  }
}

Response Fields:

FieldTypeDescription
messagestringResponse message
data.access_tokenstringJWT token to use in Authorization header
data.token_typestringToken type - always "Bearer"
data.expires_innumberToken lifetime in seconds (3600 = 1 hour)

Using the Access Token

Include both the token and API key in all subsequent API requests:

Required Headers

Authorization: Bearer YOUR_ACCESS_TOKEN
x-api-key: YOUR_API_KEY
Content-Type: application/json  # For POST/PUT requests

Example API Request

curl -X POST https://api.balampay.com/v1/users \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "idempotency-key: unique-key-123" \
  -d '{
    "type": "individual",
    "email": "[email protected]",
    "phone_number": "+1234567890",
    "first_name": "John",
    "last_name": "Doe",
    "country": "US"
  }'

Authentication in Code (Node.js)

// Authenticate and get token
async function authenticate() {
  const response = await fetch('https://api.balampay.com/auth', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': process.env.KIRA_API_KEY
    },
    body: JSON.stringify({
      client_id: process.env.KIRA_CLIENT_ID,
      password: process.env.KIRA_PASSWORD
    })
  });

  if (!response.ok) {
    throw new Error('Authentication failed');
  }

  const result = await response.json();
  return result.data.access_token;
}

// Make API request with authentication
async function createUser(userData) {
  const token = await authenticate();

  const response = await fetch('https://api.balampay.com/v1/users', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'x-api-key': process.env.KIRA_API_KEY,
      'Content-Type': 'application/json',
      'idempotency-key': `user-${Date.now()}`
    },
    body: JSON.stringify(userData)
  });

  return await response.json();
}

// Handle token expiration with automatic retry
async function makeAuthenticatedRequest(url, options) {
  let token = cachedToken;

  try {
    const response = await fetch(url, {
      ...options,
      headers: {
        'Authorization': `Bearer ${token}`,
        'x-api-key': process.env.KIRA_API_KEY,
        ...options.headers
      }
    });

    // If token expired, re-authenticate and retry
    if (response.status === 401) {
      console.log('Token expired, re-authenticating...');
      token = await authenticate();
      cachedToken = token;

      // Retry request with new token
      return await fetch(url, {
        ...options,
        headers: {
          'Authorization': `Bearer ${token}`,
          'x-api-key': process.env.KIRA_API_KEY,
          ...options.headers
        }
      });
    }

    return response;
  } catch (error) {
    console.error('Request failed:', error);
    throw error;
  }
}

Token Expiration

Access tokens expire after 1 hour (3600 seconds). When expired, you'll receive:

Status: 401 Unauthorized

{
  "message": "The incoming token has expired"
}

Solution: Re-authenticate to get a new token (see code example above for automatic retry).

Error Responses

Invalid Credentials

Status: 401 Unauthorized

{
  "code": "unauthorized",
  "message": "Invalid client ID or password"
}

Solution: Verify your credentials with Kira support

Missing API Key

Status: 401 Unauthorized

{
  "code": "unauthorized",
  "message": "Invalid API Key"
}

Solution: Include the correct API key in the x-api-key header

Missing Authorization Header

Status: 401 Unauthorized

{
  "code": "unauthorized",
  "message": "No authorization token provided"
}

Solution: Include Authorization: Bearer YOUR_TOKEN header

Security Best Practices

  1. Store credentials securely

    • Use environment variables
    • Never commit to version control
    • Use secrets management in production (AWS Secrets Manager, Vault, etc.)
  2. Use HTTPS only

    • All API requests must use HTTPS
  3. Implement token caching

    • Cache and reuse tokens until expiration
    • Don't authenticate for every request
  4. Handle token refresh

    • Implement automatic token refresh on 401 errors
  5. Rotate credentials periodically

    • Change password regularly
    • Request new API keys periodically

Rate Limits

API requests are subject to rate limiting enforced per API key through usage plans.

Default Limits

ParameterValue
Rate limit10 requests/second
Burst limit2 concurrent requests
Quota10,000 requests/week

Note: Rate limits may vary by client. Contact your account manager if you need higher limits.

Rate Limit Headers

All API responses include standard rate limit headers:

HeaderDescription
RateLimit-LimitMaximum requests allowed in the current window
RateLimit-RemainingRemaining requests in the current window
RateLimit-ResetTime (in seconds) until the rate limit resets
Retry-AfterSeconds to wait before retrying (only on 429 responses)

Handling Rate Limits

When you exceed the rate limit, the API returns:

Status: 429 Too Many Requests

Solution: Wait for the duration specified in the Retry-After header before retrying. Implement exponential backoff for robust handling.

async function makeRequestWithRetry(url, options, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, options);

    if (response.status === 429) {
      const retryAfter = response.headers.get('Retry-After') || 1;
      console.log(`Rate limited. Retrying after ${retryAfter}s...`);
      await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
      continue;
    }

    return response;
  }

  throw new Error('Max retries exceeded');
}

Sandbox Environment

Base URLs

EnvironmentBase URL
Productionhttps://api.balampay.com
Sandboxhttps://api.balampay.com/sandbox

The /sandbox prefix applies to all endpoints, not just /auth:

  • Auth: POST https://api.balampay.com/sandbox/auth
  • Users: POST https://api.balampay.com/sandbox/v1/users
  • Virtual Accounts: POST https://api.balampay.com/sandbox/v1/virtual-accounts

Sandbox Behavior

Sandbox is a fully isolated environment for testing. Key differences from production:

  • User verification is automatically approved (no real KYC processing)
  • Webhooks fire immediately for user creation and verification events
  • Bank providers: Only slovak_savings_bank is available for virtual accounts
  • Data isolation: Sandbox data is completely separate from production

Tip: Use sandbox to validate your full integration flow before going live.


Environment Setup

Create a .env file (never commit to git):

KIRA_CLIENT_ID=your-client-id-uuid
KIRA_PASSWORD=your-password
KIRA_API_KEY=your-api-key
KIRA_API_URL=https://api.balampay.com

Testing Authentication

# Test authentication
curl --location 'https://api.balampay.com/auth' \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: YOUR_API_KEY' \
  --data '{
    "client_id": "your-client-id",
    "password": "your-password"
  }'

# Expected response:
# {
#   "message": "Auth token",
#   "data": {
#     "access_token": "eyJ...",
#     "expires_in": 3600,
#     "token_type": "Bearer"
#   }
# }

Next Steps

Once authenticated:

  1. Create users
  2. Initiate identity verification
  3. Create virtual accounts

Support

  • Email: [email protected]
  • Verify credentials are correct
  • Check you're using both Authorization and x-api-key headers