Skip to main content

Sites API

Complete reference for managing analytics sites, domains, UTM mappings, and pixel installation.

Overview​

The Sites API allows you to:

  • Create and manage analytics sites
  • Configure authorized domains for tracking
  • Set up custom UTM parameter mappings
  • Generate and verify pixel installation

Base path: /sites


Site Endpoints​

List Sites​

GET /sites

Returns all sites accessible by the current user.

Response:

{
"success": true,
"data": {
"sites": [
{
"id": "acme-corp",
"name": "ACME Corporation",
"domains": ["www.acme.com", "shop.acme.com"],
"timezone": "Europe/Madrid",
"currency": "EUR",
"is_active": true,
"created_at": "2024-01-15T10:00:00Z"
}
],
"total": 1
}
}

Create Site​

POST /sites

Creates a new analytics site within your organization.

Required scope: write

Request Body:

{
"name": "My New Site",
"domains": ["www.example.com", "example.com"],
"timezone": "Europe/Madrid",
"currency": "EUR"
}
FieldTypeRequiredDescription
namestringYesSite display name (1-255 chars)
domainsstring[]NoAuthorized domains for tracking
timezonestringNoIANA timezone (default: UTC)
currencystringNoISO 4217 currency code (default: EUR)

Response (201 Created):

{
"success": true,
"data": {
"id": "my-new-site",
"name": "My New Site",
"domains": ["www.example.com", "example.com"],
"timezone": "Europe/Madrid",
"currency": "EUR",
"is_active": true,
"created_at": "2025-01-10T14:30:00Z"
}
}

Note: The id is auto-generated as a slug from the site name.


Get Site​

GET /sites/{site_id}

Returns detailed information about a specific site.

Response:

{
"success": true,
"data": {
"id": "acme-corp",
"name": "ACME Corporation",
"domains": ["www.acme.com", "shop.acme.com"],
"timezone": "Europe/Madrid",
"currency": "EUR",
"is_active": true,
"created_at": "2024-01-15T10:00:00Z",
"updated_at": "2025-01-08T09:15:00Z"
}
}

Update Site​

PATCH /sites/{site_id}

Updates site settings.

Request Body:

{
"name": "ACME Corp (Updated)",
"timezone": "America/New_York",
"currency": "USD"
}

All fields are optional. Only provided fields are updated.


Delete Site​

DELETE /sites/{site_id}

Deactivates a site (soft delete).

Required scope: write

Response:

{
"success": true,
"data": {
"deleted": true,
"site_id": "acme-corp"
}
}

Domain Endpoints​

Domains authorize which websites can send tracking data to a site.

List Domains​

GET /sites/{site_id}/domains

Response:

{
"success": true,
"data": {
"domains": [
{
"id": 1,
"domain": "www.acme.com",
"is_active": true,
"created_at": "2024-01-15T10:00:00Z"
},
{
"id": 2,
"domain": "shop.acme.com",
"is_active": true,
"created_at": "2024-01-15T10:00:00Z"
}
],
"total": 2
}
}

Add Domain​

POST /sites/{site_id}/domains

Request Body:

{
"domain": "blog.acme.com"
}

Response (201 Created):

{
"success": true,
"data": {
"id": 3,
"domain": "blog.acme.com",
"is_active": true,
"created_at": "2025-01-10T14:30:00Z"
}
}

Remove Domain​

DELETE /sites/{site_id}/domains/{domain}

Response:

{
"success": true,
"data": {
"removed": true,
"domain": "blog.acme.com"
}
}

UTM Mapping Endpoints​

UTM mappings allow custom URL parameters to be mapped to standard UTM fields.

List UTM Mappings​

GET /sites/{site_id}/utm-mappings

Response:

{
"success": true,
"data": {
"mappings": [
{
"id": 1,
"custom_param": "campaign_id",
"maps_to": "utm_campaign",
"is_active": true,
"overrides_explicit": false,
"created_at": "2024-06-01T12:00:00Z"
},
{
"id": 2,
"custom_param": "ad_source",
"maps_to": "utm_source",
"is_active": true,
"overrides_explicit": true,
"created_at": "2024-06-01T12:00:00Z"
}
],
"total": 2
}
}

Add UTM Mapping​

POST /sites/{site_id}/utm-mappings

Request Body:

{
"custom_param": "gclid_source",
"maps_to": "utm_source"
}
FieldTypeDescription
custom_paramstringYour custom URL parameter name
maps_toenumStandard UTM field: utm_source, utm_medium, utm_campaign, utm_term, utm_content
overrides_explicitbooleanOptional, default false. When true, the mapped value is written even if the URL already carries the target UTM — the API name of the dashboard's Override the UTM if the URL already has one option. See UTM Mapping rules.

A POST for a custom_param that already exists updates that mapping, and sets overrides_explicit to the value sent — false if you omit it. To change only the override on an existing mapping, use PATCH.

Example Use Case:

If your ad platform uses ?src=google instead of ?utm_source=google, create a mapping:

{
"custom_param": "src",
"maps_to": "utm_source"
}

Now ?src=google will be treated as ?utm_source=google.

If the URL can also carry a utm_source you don't control — a Google Shopping or Performance Max product feed, for example — send "overrides_explicit": true so the value of src replaces it. Without it, an explicit UTM already in the URL wins and the mapping is skipped.


Update UTM Mapping​

PATCH /sites/{site_id}/utm-mappings/{mapping_id}

Request Body:

{
"maps_to": "utm_medium",
"is_active": false
}

Every field is optional; only the ones you send change. To turn the override on or off for one mapping:

{
"overrides_explicit": true
}

Changes apply to new traffic within about 5 minutes and are not retroactive.


Remove UTM Mapping​

DELETE /sites/{site_id}/utm-mappings/{custom_param}

Site User Endpoints​

Manage user access to a specific site. Org-level membership is managed via the Organizations API; these endpoints control which users in the org can see and act on this site, with a per-site role.

Permissions

List operations require any read scope. Mutations (POST/PATCH/DELETE) require the sites:write scope and the accounts:manage_users permission (or admin).

List Site Users​

GET /sites/{site_id}/users

Response:

{
"success": true,
"data": {
"users": [
{
"user_id": 42,
"email": "alice@acme.com",
"name": "Alice",
"role": "admin",
"created_at": "2025-01-05T10:00:00Z"
},
{
"user_id": 87,
"email": "bob@acme.com",
"name": "Bob",
"role": "viewer",
"created_at": "2025-02-12T09:30:00Z"
}
],
"total": 2
}
}

Add User to Site​

POST /sites/{site_id}/users

Request Body:

FieldTypeRequiredDescription
user_idintegerYesID of the user to add
rolestringNoviewer, editor, or admin (default: viewer)

Response (201 Created): Single AccountUserInfo object (same shape as items in List response).

Returns 404 if the user does not exist, 409 if the user already has access.

Update User Role​

PATCH /sites/{site_id}/users/{user_id}

Request Body:

FieldTypeRequiredDescription
rolestringYesviewer, editor, or admin

Response: Updated AccountUserInfo object.

Remove User from Site​

DELETE /sites/{site_id}/users/{user_id}

Response:

{
"success": true,
"data": { "removed": true, "user_id": 87 }
}

Pixel Code Endpoints​

Get Pixel Code​

GET /sites/{site_id}/pixel

Returns the tracking pixel installation code.

Response:

{
"success": true,
"data": {
"site_id": "acme-corp",
"script_tag": "<script src=\"https://t.sealmetrics.com/t.js?id=acme-corp\" defer></script>",
"tracker_url": "https://t.sealmetrics.com/t.js?id=acme-corp",
"instructions": "Add this script tag to your website's <head> section."
}
}

Get Pixel Status​

GET /sites/{site_id}/pixel/status

Check if the tracking pixel is installed and receiving data.

Response:

{
"success": true,
"data": {
"site_id": "acme-corp",
"installed": true,
"first_hit_at": "2024-01-15T10:05:00Z",
"last_hit_at": "2025-01-10T14:28:00Z",
"total_hits": 1523456
}
}
FieldDescription
installedtrue if pixel has received any hits
first_hit_atTimestamp of the first hit received
last_hit_atTimestamp of the most recent hit
total_hitsTotal hits in the last 14 days

Timezones​

List Available Timezones​

GET /sites/config/timezones

Returns all available IANA timezone identifiers.

Response:

{
"success": true,
"data": {
"timezones": [
{
"timezone": "Europe/Madrid",
"country_code": "ES",
"country_name": "Spain"
},
{
"timezone": "America/New_York",
"country_code": "US",
"country_name": "United States"
}
],
"total": 400
}
}

Error Codes​

HTTP CodeError CodeDescription
400invalid_timezoneInvalid IANA timezone identifier
400invalid_domainInvalid domain format
403forbiddenInsufficient permissions
404not_foundSite or resource not found

Code Examples​

Python​

import requests

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

# Create site
response = requests.post(
f"{BASE_URL}/sites",
headers={"X-API-Key": API_KEY},
json={
"name": "My E-commerce Site",
"domains": ["www.myshop.com"],
"timezone": "Europe/Madrid"
}
)
site = response.json()["data"]
print(f"Created site: {site['id']}")

# Add domain
requests.post(
f"{BASE_URL}/sites/{site['id']}/domains",
headers={"X-API-Key": API_KEY},
json={"domain": "shop.myshop.com"}
)

# Get pixel code
pixel = requests.get(
f"{BASE_URL}/sites/{site['id']}/pixel",
headers={"X-API-Key": API_KEY}
).json()["data"]
print(pixel["script_tag"])

JavaScript​

const API_KEY = 'sm_your_api_key';
const BASE_URL = 'https://my.sealmetrics.com/api/v1';

// Create site
const response = await fetch(`${BASE_URL}/sites`, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'My E-commerce Site',
domains: ['www.myshop.com'],
timezone: 'Europe/Madrid'
})
});

const { data: site } = await response.json();
console.log(`Created site: ${site.id}`);

// Check pixel status
const statusResponse = await fetch(
`${BASE_URL}/sites/${site.id}/pixel/status`,
{ headers: { 'X-API-Key': API_KEY } }
);
const { data: status } = await statusResponse.json();
console.log(`Pixel installed: ${status.installed}`);
Written and maintained by the Sealmetrics Team