Authentication
The API supports two authentication methods: API Keys and JWT tokens.
API Keys
API keys are the recommended method for server-to-server integrations.
Obtaining an API Key
- Log in to Sealmetrics dashboard
- Go to Settings → API Keys
- Click Generate New Key
- Copy the key immediately (it won't be shown again)
Using API Keys
Include the key in the X-API-Key header:
curl -X GET "https://api.sealmetrics.com/api/v1/sites/YOUR_SITE_ID/stats" \
-H "X-API-Key: sm_your_api_key_here"
API Key Format
All API keys use the sm_ prefix:
sm_abc123def456ghi789...
Keys are 64 characters long and contain only alphanumeric characters after the prefix.
API Key Security
- Keys are hashed before storage (we cannot retrieve your key)
- Keys can be revoked at any time from the dashboard
- Set expiration dates for temporary access
- Each key is scoped to specific sites
JWT Bearer Tokens
JWT tokens are used for user-authenticated sessions (dashboard, mobile apps).
Obtaining a Token
curl -X POST "https://api.sealmetrics.com/api/v1/auth/token" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "your_password"
}'
Response:
{
"access_token": "<access_token>",
"token_type": "bearer",
"expires_in": 900,
"refresh_token": "<refresh_token>"
}
Using JWT Tokens
Include the token in the Authorization header:
curl -X GET "https://api.sealmetrics.com/api/v1/sites/YOUR_SITE_ID/stats" \
-H "Authorization: Bearer <your_access_token>"
Token Refresh
Access tokens expire after 15 minutes. Use the refresh token to obtain a new access token:
curl -X POST "https://api.sealmetrics.com/api/v1/auth/refresh" \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "<your_refresh_token>"
}'
JWT Claims
The access token contains:
| Claim | Description |
|---|---|
sub | User ID |
email | User email |
account_ids | List of accessible site IDs |
exp | Expiration timestamp |
iat | Issued at timestamp |
Authentication Errors
| HTTP Code | Error Code | Description |
|---|---|---|
| 401 | missing_credentials | No API key or token provided |
| 401 | invalid_api_key | API key not found or revoked |
| 401 | invalid_token | JWT token is malformed |
| 401 | token_expired | JWT token has expired |
| 403 | insufficient_scope | Valid auth but no access to this resource |
Example error response:
{
"error": {
"code": "invalid_api_key",
"message": "The provided API key is invalid or has been revoked"
},
"request_id": "req_abc123"
}
Best Practices
For API Keys
- Never commit keys to git - Use environment variables
- Rotate keys periodically - Generate new keys and revoke old ones
- Use separate keys per environment - Different keys for dev, staging, production
- Set minimum required scope - Only grant access to needed sites
For JWT Tokens
- Store tokens securely - Use httpOnly cookies or secure storage
- Implement token refresh - Don't wait for expiration errors
- Handle 401 gracefully - Redirect to login or refresh automatically
- Clear tokens on logout - Call the logout endpoint
Code Examples
Python
import requests
API_KEY = "sm_your_api_key_here"
BASE_URL = "https://api.sealmetrics.com/api/v1"
def get_stats(site_id: str, period: str = "7d"):
response = requests.get(
f"{BASE_URL}/sites/{site_id}/stats",
headers={"X-API-Key": API_KEY},
params={"period": period}
)
response.raise_for_status()
return response.json()
JavaScript / Node.js
const API_KEY = 'sm_your_api_key_here';
const BASE_URL = 'https://api.sealmetrics.com/api/v1';
async function getStats(siteId, period = '7d') {
const response = await fetch(
`${BASE_URL}/sites/${siteId}/stats?period=${period}`,
{
headers: { 'X-API-Key': API_KEY }
}
);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
PHP
<?php
$apiKey = 'sm_your_api_key_here';
$baseUrl = 'https://api.sealmetrics.com/api/v1';
function getStats($siteId, $period = '7d') {
global $apiKey, $baseUrl;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$baseUrl/sites/$siteId/stats?period=$period");
curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-API-Key: $apiKey"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}