Authentication
Secure your API requests with API keys and understand permission scopes.
API Keys
Harpoon uses API keys to authenticate requests. You can create and manage API keys from your dashboard.
Key Types
There are two types of API keys designed for different use cases:
| Type | Prefix | Usage | Best For |
|---|---|---|---|
| Secret Key | hpn_*_sk_ | Full API access. Server-side only. | Backend servers, webhooks, reconciliation |
| Public Key | hpn_*_pk_ | Limited access. Safe for browser use. | Frontend apps, mobile apps, checkout pages |
Full API access for server-side operations. Never expose in browser code.
Can:
- • Initialize payments with custom webhooks
- • List all transactions
- • Reconcile payments manually
- • Configure webhook endpoints
Browser-safe key for frontend integrations. Limited permissions.
Can:
- • Initialize payments (no custom webhook)
- • Check individual transaction status
Cannot:
- • Set custom webhook URLs
- • List all transactions
- • Access reports or sensitive data
Using API Keys
Include your API key in the Authorization header as a Bearer token:
Authorization: Bearer hpn_live_sk_your_api_key_hereExample Request
curl -X POST https://api.harpoonsms.com/v1/transactions/initialize
-H "Authorization: Bearer hpn_live_sk_xxxxxxxxxxxxx"
-H "Content-Type: application/json"
-d '{
"amount": "100.00",
"description": "Test payment"
}'Permission Scopes
API keys can be configured with specific scopes to limit their permissions. This follows the principle of least privilege - only grant the permissions your integration needs.
| Scope | Description | Browser Safe |
|---|---|---|
transactions:read | Read transaction status (single transaction lookup) | Yes |
transactions:initialize | Initialize payments only (no custom webhooks) | Yes |
transactions:write | Full transaction access: initialize, list, reconcile | No |
webhooks:manage | Create, update, delete, and test webhook endpoints | No |
Default Scopes
When creating keys, default scopes are assigned based on key type:
| Key Type | Default Scopes |
|---|---|
| Secret Key (sk) | transactions:read, transactions:write |
| Public Key (pk) | transactions:read, transactions:initialize |
Public Key Restrictions
Public keys can only have browser-safe scopes (transactions:read, transactions:initialize).
Attempting to assign other scopes to a public key will result in an error.
Scope Errors
If your API key doesn’t have the required scope for an operation, you’ll receive a 403 Forbidden response:
{
"error": "Forbidden",
"message": "API key does not have transactions:write scope"
}IP Whitelisting
For additional security, you can restrict API access to specific IP addresses or CIDR ranges. Configure IP whitelisting from your API keys dashboard.
Supported formats:
- Single IPv4 address:
192.168.1.100 - CIDR range:
192.168.1.0/24
When IP whitelisting is enabled, requests from non-whitelisted IPs will receive a 403 Forbidden response:
{
"error": "Forbidden",
"message": "IP address not whitelisted"
}Rate Limiting
API requests are rate limited to protect the service and ensure fair usage. Rate limits are applied per API key.
| Key Type | Default Limit |
|---|---|
| Secret Key (sk) | 100 requests/minute |
| Public Key (pk) | 100 requests/minute |
When you exceed the rate limit, you’ll receive a 429 Too Many Requests response:
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Please try again later."
}The response includes headers to help you manage your request rate:
X-RateLimit-Limit: Your rate limit per minuteX-RateLimit-Remaining: Requests remaining in current windowX-RateLimit-Reset: Unix timestamp when the limit resets
Creating API Keys
Via Dashboard
- Go to Settings → API Keys
- Click “Create API Key”
- Enter a name and select the environment
- Choose the required scopes
- Click “Create” and save the key immediately (it won’t be shown again)
Important
The full API key is only shown once when created. Store it securely immediately - you won't be able to retrieve it again.
Browser Integration
Public keys are designed for browser/frontend integrations. Here’s how to use them safely:
Basic Browser Example
// Use a PUBLIC key - safe to expose in browser code
const HARPOON_PUBLIC_KEY = 'hpn_live_pk_your_key_here';
async function initializePayment(amount, phone) {
const response = await fetch('https://api.harpoonsms.com/v1/transactions/initialize', {
method: 'POST',
headers: {
'Authorization': `Bearer ${HARPOON_PUBLIC_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: amount,
currency: 'GHS',
phone_number: phone,
description: 'Order payment'
// Note: webhook_url is NOT allowed with public keys
})
});
return response.json();
}
// Poll for payment status
async function checkPaymentStatus(reference) {
const response = await fetch(`https://api.harpoonsms.com/v1/transactions/${reference}`, {
headers: { 'Authorization': `Bearer ${HARPOON_PUBLIC_KEY}` }
});
return response.json();
}Receiving Verifications
When using public keys, you have two options for receiving payment verifications:
- Polling - Check transaction status periodically using
transactions:read - Pre-configured Webhooks - Set up webhooks via the dashboard (they’ll fire for all payments)
// Option 1: Polling for status
async function waitForPayment(reference, maxWaitMs = 300000) {
const startTime = Date.now();
while (Date.now() - startTime < maxWaitMs) {
const result = await checkPaymentStatus(reference);
if (['SUCCESS', 'PARTIAL', 'OVERPAID'].includes(result.data.status)) {
return { success: true, data: result.data };
}
if (['FAILED', 'EXPIRED', 'CANCELLED'].includes(result.data.status)) {
return { success: false, data: result.data };
}
await new Promise(resolve => setTimeout(resolve, 3000)); // Poll every 3s
}
throw new Error('Payment verification timed out');
}Public keys cannot set custom webhook URLs for security reasons. Configure webhooks via the dashboard or with a secret key.
Revoking API Keys
If you suspect a key has been compromised, revoke it immediately:
- Go to Settings → API Keys
- Find the key you want to revoke
- Click the delete/revoke button
- Confirm the revocation
Revoked keys are immediately invalidated. Any requests using the revoked key will receive a 401 Unauthorized response.
Next Steps
- Learn the Payments API - Create and verify payments
- Set up webhooks - Receive payment notifications