Authentication
Every request to the Commerce API requires authentication using a secret API key sent as a bearer token. This guide explains how authentication works, how to securely configure your API key, and what happens behind the scenes when you make authenticated requests.
How it works
Commerce uses bearer token authentication with a session-based authorization model. When you make a request with your secret key, Commerce validates it, creates a temporary session, and authorizes the request. Sessions expire after a short period, so every request goes through this validation process—you don't need to manage sessions yourself.
Here's what happens on each request:
- You send your secret key in the
Authorizationheader as a bearer token - Commerce validates the key and checks it against your application record
- A session is created with your application context and permissions
- The request is authorized and processed with your application's scope
- The session expires automatically after processing (or after ~60 minutes for cached sessions)
This stateless approach means you don't track tokens or refresh credentials—just include your secret key with every request, and Commerce handles the rest.
API keys
You'll find your API keys in the Commerce dashboard under API settings. Commerce provides two types of keys:
Secret keys - Use these for server-side requests. They have full API access and should never be exposed in client-side code, mobile apps, or version control. Secret keys start with sk_live_ for production or sk_test_ for testing.
Publishable keys - Use these for client-side code where the key might be visible (web frontends, mobile apps). These keys have limited permissions and cannot perform sensitive operations. Publishable keys start with pk_live_ or pk_test_.
For most backend integrations, you'll use secret keys exclusively. The examples in this guide focus on secret key authentication.
Bearer token authentication
Include your secret key in the Authorization header of every request using the bearer token format:
Authorization: Bearer YOUR_SECRET_KEY
The API expects the header value to be exactly Bearer (with a space) followed by your secret key. If the header is missing, malformed, or contains an invalid key, Commerce returns a 401 Unauthorized error.
Example request
Authenticated request
curl https://api.zebo.dev/orders/new \
-H "Authorization: Bearer sk_live_abc123def456" \
-H "Content-Type: application/json" \
-d '{
"execute_payment": true,
"customer_data": {
"name": "Gloria Kesewaa",
"phone_number": "+233544998605"
},
"payment_method_data": {
"type": "mobile_money",
"mobile_money": {
"issuer": "mtn",
"number": "0544998605"
}
},
"line_items": [
{
"type": "product",
"product": {
"name": "Premium Subscription",
"price": { "currency": "ghs", "value": 5000 },
"quantity": 1
}
}
]
}'
SDK configuration
All official Commerce SDKs handle authentication automatically once you provide your secret key during initialization. The SDK includes the bearer token in every request's Authorization header.
Environment variables (recommended)
Store your secret key in environment variables rather than hardcoding it in your source code:
# .env file
COMMERCE_API_KEY=sk_live_your_secret_key_here
Then load it in your application:
SDK initialization
import Commerce from '@example/commerce-api'
const client = new Commerce(process.env.COMMERCE_API_KEY!)
Configuration files
For production deployments, use your platform's secret management:
- AWS: AWS Secrets Manager or Parameter Store
- Google Cloud: Secret Manager
- Azure: Key Vault
- Heroku: Config Vars
- Vercel/Netlify: Environment Variables
Never commit API keys to version control. Add .env files to your .gitignore:
# .gitignore
.env
.env.local
.env.production
Session lifecycle
When Commerce receives your bearer token, it creates an authenticated session:
-
Token validation - Commerce verifies the key exists and is active
-
Application lookup - The key is linked to your application and its permissions
-
Session creation - A temporary session is created with:
- Session ID (for logging and debugging)
- Application context (your app ID, name, permissions)
- Expiration time (approximately 60 minutes from creation)
- Multi-use flag (sessions can handle multiple requests)
-
Request processing - Your request is processed with the session's permissions
-
Automatic expiration - Sessions expire automatically; you don't manage them
Sessions are created on-demand and cached briefly to improve performance. You don't need to track or refresh sessions—just send your secret key with each request, and Commerce handles session management transparently.
Test vs production keys
Commerce provides separate API keys for testing and production:
Test keys (sk_test_...)
- Use these in development and staging environments
- Test transactions don't process real payments
- Test keys work with test phone numbers (e.g.,
0242000003for MTN) - OTP is always
000000in test mode - Test data is isolated from production
Production keys (sk_live_...)
- Use these in production environments only
- Transactions process real payments
- Never use production keys in development or share them publicly
- Monitor production key usage in the Commerce dashboard
Switching environments
Environment-based keys
const apiKey = process.env.NODE_ENV === 'production'
? process.env.COMMERCE_LIVE_KEY!
: process.env.COMMERCE_TEST_KEY!
const client = new Commerce(apiKey)
Error handling
Commerce returns specific errors when authentication fails. Handle these appropriately in your application:
401 Unauthorized
Cause: Missing, invalid, or expired API key
Response:
{
"error": {
"code": "authentication_failed",
"message": "Invalid or missing API key",
"type": "authentication_error"
}
}
Common causes:
- Authorization header is missing
- Bearer token format is incorrect (missing "Bearer " prefix)
- API key is invalid or has been deleted
- Using a test key in production or vice versa
Fix: Verify your API key is correct and properly formatted in the Authorization header.
403 Forbidden
Cause: Valid API key but insufficient permissions for the requested operation
Response:
{
"error": {
"code": "permission_denied",
"message": "This API key does not have permission to perform this action",
"type": "authorization_error"
}
}
Common causes:
- Using a publishable key for server-side operations
- API key permissions have been restricted in the dashboard
- Attempting operations outside your application's scope
Fix: Use a secret key with appropriate permissions, or update key permissions in the dashboard.
Handling authentication errors
Error handling
try {
const order = await client.orders.create(params)
} catch (error) {
if (error.type === 'authentication_error') {
console.error('Authentication failed. Check your API key.')
// Log error and alert your team
} else if (error.type === 'authorization_error') {
console.error('Insufficient permissions for this operation.')
// Check key permissions in dashboard
}
}
Security best practices
Never expose secret keys: Don't include secret keys in client-side code, mobile apps, or public repositories. Use environment variables and secret management services.
Rotate keys regularly: Generate new keys periodically and when team members leave. Update your applications before deleting old keys.
Use test keys in development: Always use test keys (sk_test_...) in development and staging. Never use production keys outside production environments.
Monitor key usage: Check the Commerce dashboard regularly for unusual API activity. Set up alerts for failed authentication attempts.
Restrict key permissions: If you need keys with limited scope, create separate keys with specific permissions in the dashboard rather than sharing full-access keys.
Secure your environment variables: Protect .env files with proper file permissions. On servers, ensure only your application user can read secret files.
Handle 401 errors gracefully: Log authentication failures and alert your team. If you see repeated 401 errors, your key may have been compromised—rotate immediately.
Next steps
- Quickstart - Make your first API request
- Orders API - Create and manage orders
- Accept a payment - Complete payment flow walkthrough
- SDKs - Official client libraries for your language
Your API keys are available in the Commerce dashboard under API settings. Start with test keys for development, then switch to production keys when you're ready to go live.