Authentication

Authentication

Learn how to authenticate your API requests with SerixPay. We support two authentication methods: API Keys and OAuth 2.0 Client Credentials.

API Keys

Simple authentication using static API keys. Best for quick integration.

pk_live_* / pk_test_*

OAuth 2.0 (Recommended)

Industry-standard OAuth 2.0 Client Credentials flow. Similar to Safaricom M-PESA API.

ck_live_* / ck_test_*

OAuth 2.0 Client Credentials

The OAuth 2.0 Client Credentials flow is the recommended way to authenticate. It uses short-lived access tokens that expire after 1 hour, providing better security. This pattern is similar to how Safaricom's M-PESA API works.

Step 1: Get Consumer Credentials

Create an OAuth client from your dashboard to get your consumer_key and consumer_secret.

Consumer Keyck_test_DXatcpzyI4dM...
Consumer Secretcs_TkdodC6iCjhg...

Step 2: Generate Access Token

Exchange your consumer credentials for an access token. Create a Basic Auth header by Base64 encoding consumer_key:consumer_secret:

How Basic Auth Works

  1. Concatenate your consumer key and secret with a colon: consumer_key:consumer_secret
  2. Base64 encode the concatenated string
  3. Add the encoded string to the Authorization header: Basic <encoded_string>

cURL

get-token.shbash
# Base64 encode consumer_key:consumer_secret
CONSUMER_KEY="ck_test_DXatcpzyI4dM..."
CONSUMER_SECRET="cs_TkdodC6iCjhg..."
CREDENTIALS=$(echo -n "$CONSUMER_KEY:$CONSUMER_SECRET" | base64)
# Request access token
curl -X POST https://api.serixpay.com/api/v1/auth/token \
-H "Authorization: Basic $CREDENTIALS" \
-H "Content-Type: application/json" \
-d '{"grant_type": "client_credentials"}'

Node.js

get-token.jsjavascript
const consumerKey = 'ck_test_DXatcpzyI4dM...';
const consumerSecret = 'cs_TkdodC6iCjhg...';
// Create Base64 encoded credentials
const credentials = Buffer.from(`${consumerKey}:${consumerSecret}`).toString('base64');
const response = await fetch('https://api.serixpay.com/api/v1/auth/token', {
method: 'POST',
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ grant_type: 'client_credentials' }),
});
const { access_token, expires_in } = await response.json();
console.log('Access Token:', access_token);
console.log('Expires in:', expires_in, 'seconds');

Python

get_token.pypython
import base64
import requests
consumer_key = 'ck_test_DXatcpzyI4dM...'
consumer_secret = 'cs_TkdodC6iCjhg...'
# Create Base64 encoded credentials
credentials = base64.b64encode(f'{consumer_key}:{consumer_secret}'.encode()).decode()
response = requests.post(
'https://api.serixpay.com/api/v1/auth/token',
headers={
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json',
},
json={'grant_type': 'client_credentials'}
)
data = response.json()
access_token = data['access_token']
print(f'Access Token: {access_token}')

Response:

{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}

Step 3: Use Access Token

Use the access token in the Authorization header for all API requests:

charge-card.shbash
curl -X POST https://api.serixpay.com/api/v1/payments/charge \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"amount": 100,
"currency": "USD",
"reference": "ORDER-001",
"customer": {
"email": "customer@example.com",
"firstName": "John",
"lastName": "Doe"
},
"card": {
"number": "4242424242424242",
"expiry": "12/26",
"cvv": "123"
}
}'

Token Expiration

Access tokens expire after 1 hour. Your application should handle token refresh by requesting a new token before the current one expires.

API Keys (Simple Method)

For simpler integrations, you can use static API keys directly in the Authorization header. You can create and manage API keys from your dashboard.

Header Format

Authorization: Bearer pk_live_your_api_key_here

Test Keys

pk_test_*
  • • Use for development and testing
  • • No real payments are processed
  • • Use sandbox phone numbers and test cards
  • • Unlimited test transactions

Live Keys

pk_live_*
  • • Use for production only
  • • Real payments are processed
  • • Use real customer phone numbers
  • • Standard transaction fees apply

Example Request

request.shbash
curl -X POST https://api.serixpay.com/api/v1/init-payment \
-H "Authorization: Bearer pk_test_abc123xyz" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "254712345678",
"amount": 100,
"orderId": "ORDER-001"
}'

Security Best Practices

Never Expose API Keys

Never include API keys in client-side code, public repositories, or anywhere they could be exposed. Always make API calls from your server.

Don't: Client-side API calls

Never call the SerixPay API directly from browser JavaScript, mobile apps, or any client-side code.

Do: Server-side API calls

Make all API calls from your backend server where the API key can be stored securely as an environment variable.

Environment Variables

Store your credentials securely in environment variables:

.envbash
# .env file (never commit this to git)
# OAuth 2.0 Credentials (Recommended)
SERIXPAY_CONSUMER_KEY=ck_test_your_consumer_key
SERIXPAY_CONSUMER_SECRET=cs_your_consumer_secret
# OR API Key (Simple method)
SERIXPAY_API_KEY=pk_test_your_api_key_here
# Webhook verification
SERIXPAY_WEBHOOK_SECRET=whsec_your_webhook_secret

Access in your code:

// OAuth credentials
const consumerKey = process.env.SERIXPAY_CONSUMER_KEY;
const consumerSecret = process.env.SERIXPAY_CONSUMER_SECRET;
// OR API key
const apiKey = process.env.SERIXPAY_API_KEY;

Authentication Errors

Common authentication error responses:

401Missing or invalid API key
{
"success": false,
"error": "Invalid API key provided",
"code": "INVALID_API_KEY"
}
403API key revoked or expired
{
"success": false,
"error": "API key has been revoked",
"code": "API_KEY_REVOKED"
}

Webhook Signature Verification

Verify webhook signatures to ensure requests come from SerixPay:

webhook.jsjavascript
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your webhook handler
app.post('/webhook', (req, res) => {
const signature = req.headers['x-serixpay-signature'];
if (!verifyWebhookSignature(req.body, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook...
});