Skip to main content

API Tokens

Create and manage personal API tokens for programmatic access to the Sealmetrics API.

Overview

API tokens provide:

  • Long-lived authentication for integrations
  • Scoped permissions per token
  • Optional account restrictions
  • Automatic expiration

Base path: /api-tokens


Scopes

API tokens can be granted the following permissions:

ScopeDescription
stats:readRead analytics data (traffic, conversions, pages)
sites:readRead site configuration (domains, settings)
accounts:readRead account information

Note: API tokens have read-only access. Write operations require JWT authentication via the dashboard.

List Available Scopes

GET /api-tokens/scopes

Response:

{
"data": {
"scopes": [
{
"id": "stats:read",
"name": "Stats Read",
"description": "Read analytics data"
},
{
"id": "sites:read",
"name": "Sites Read",
"description": "Read site configuration"
},
{
"id": "accounts:read",
"name": "Accounts Read",
"description": "Read account information"
}
]
}
}

List Tokens

GET /api-tokens

Query Parameters:

ParameterTypeDefaultDescription
include_inactivebooleanfalseInclude revoked tokens

Response:

{
"data": {
"tokens": [
{
"id": 1,
"name": "Production API",
"token_prefix": "sm_abc",
"scopes": ["stats:read", "sites:read", "accounts:read"],
"account_ids": ["acme-corp"],
"is_active": true,
"expires_at": "2026-01-10T00:00:00Z",
"last_used_at": "2025-01-10T14:30:00Z",
"created_at": "2025-01-01T10:00:00Z"
}
],
"total": 1
}
}

Create Token

POST /api-tokens

Request Body:

{
"name": "My Integration",
"scopes": ["stats:read", "sites:read"],
"account_ids": ["acme-corp", "other-site"],
"expires_in_days": 365
}
FieldTypeRequiredDescription
namestringYesToken name (1-255 chars)
scopesstring[]YesPermission scopes
account_idsstring[]NoRestrict to specific accounts
expires_in_daysintNoDays until expiration (default: 365)

Response (201 Created):

{
"data": {
"id": 2,
"name": "My Integration",
"token": "sm_abc123def456ghi789...",
"token_prefix": "sm_abc",
"scopes": ["stats:read", "sites:read"],
"account_ids": ["acme-corp", "other-site"],
"is_active": true,
"expires_at": "2026-01-10T00:00:00Z",
"created_at": "2025-01-10T14:30:00Z"
}
}

Important: The full token value is only returned once. Store it securely.


Get Token

GET /api-tokens/{token_id}

Response:

{
"data": {
"id": 1,
"name": "Production API",
"token_prefix": "sm_abc",
"scopes": ["stats:read", "sites:read", "accounts:read"],
"account_ids": ["acme-corp"],
"is_active": true,
"expires_at": "2026-01-10T00:00:00Z",
"last_used_at": "2025-01-10T14:30:00Z",
"created_at": "2025-01-01T10:00:00Z"
}
}

Revoke Token

DELETE /api-tokens/{token_id}

Revokes a token immediately. This action cannot be undone.

Response:

{
"data": {
"id": 1,
"name": "Production API",
"is_active": false,
"revoked_at": "2025-01-10T14:30:00Z"
}
}

Using API Tokens

Include the token in the X-API-Key header:

curl -X GET "https://my.sealmetrics.com/api/v1/stats/overview?site_id=acme" \
-H "X-API-Key: sm_abc123def456ghi789..."

Token Best Practices

1. Use Minimal Scopes

Only grant the scopes your integration needs:

{
"name": "Analytics Only",
"scopes": ["stats:read"]
}

2. Restrict to Specific Sites

If your integration only needs access to certain sites:

{
"name": "Client Dashboard",
"scopes": ["stats:read"],
"account_ids": ["client-a", "client-b"]
}

3. Set Appropriate Expiration

For temporary integrations, use short expiration:

{
"name": "Audit Script",
"scopes": ["stats:read"],
"expires_in_days": 7
}

4. Rotate Tokens Regularly

Create a new token before the old one expires:

# Create new token
new_token = create_token("Production API v2", scopes=["stats:read", "sites:read"])

# Update your application config
update_config(new_token)

# Revoke old token after confirming new one works
revoke_token(old_token_id)

5. Never Commit Tokens

Store tokens in environment variables:

# .env file (never commit!)
SEALMETRICS_API_KEY=sm_abc123...
import os
API_KEY = os.environ["SEALMETRICS_API_KEY"]

Token Errors

HTTP CodeErrorDescription
401invalid_api_keyToken not found or revoked
401token_expiredToken has expired
403insufficient_scopeToken lacks required scope
403account_not_allowedAccount not in token's allowed list

Code Examples

Python

import requests

BASE_URL = "https://my.sealmetrics.com/api/v1"

def create_api_token(auth_token: str, name: str, scopes: list) -> dict:
"""Create a new API token."""
response = requests.post(
f"{BASE_URL}/api-tokens",
headers={"Authorization": f"Bearer {auth_token}"},
json={
"name": name,
"scopes": scopes,
"expires_in_days": 365
}
)
response.raise_for_status()
return response.json()["data"]

def revoke_token(auth_token: str, token_id: int):
"""Revoke an API token."""
response = requests.delete(
f"{BASE_URL}/api-tokens/{token_id}",
headers={"Authorization": f"Bearer {auth_token}"}
)
response.raise_for_status()

JavaScript

async function createApiToken(authToken, name, scopes) {
const response = await fetch(`${BASE_URL}/api-tokens`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${authToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name,
scopes,
expires_in_days: 365
})
});

if (!response.ok) {
throw new Error(`Failed to create token: ${response.status}`);
}

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