Sites
Manage your websites and analytics properties
Overview
The Sites API allows you to create, list, update, and delete websites (analytics properties) in your Zero Trust Analytics account. Each site has a unique ID used for tracking and data retrieval.
Endpoints
GET /api/sites # List all sites
POST /api/sites # Create a new site
PATCH /api/sites # Update a site
POST /api/sites/delete # Delete a site (soft delete)
GET /api/sites/deleted # List deleted sites
POST /api/sites/restore # Restore a deleted site
Requires authentication. See Authentication.
List Sites
Get all sites in your account.
Request
curl "https://ztas.io/api/sites" \
-H "Authorization: Bearer YOUR_TOKEN"
Response
{
"sites": [
{
"id": "site_abc123",
"domain": "example.com",
"name": "Example Website",
"timezone": "America/New_York",
"public": false,
"createdAt": "2024-01-15T10:00:00.000Z",
"stats": {
"pageviews": 125432,
"visitors": 45231,
"lastPageview": "2024-12-12T16:30:00.000Z"
},
"teamMembers": 3
},
{
"id": "site_def456",
"domain": "blog.example.com",
"name": "Example Blog",
"timezone": "America/Los_Angeles",
"public": true,
"createdAt": "2024-03-20T14:00:00.000Z",
"stats": {
"pageviews": 87654,
"visitors": 32145,
"lastPageview": "2024-12-12T16:25:00.000Z"
},
"teamMembers": 2
}
]
}
Create Site
Add a new website to track analytics.
Request
curl -X POST "https://ztas.io/api/sites" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"domain": "newsite.com",
"name": "New Site",
"timezone": "America/New_York",
"public": false
}'
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
domain | string | Yes | Website domain (without protocol) |
name | string | No | Friendly name for the site (defaults to domain) |
timezone | string | No | Timezone for date/time display (default: UTC) |
public | boolean | No | Make stats publicly viewable (default: false) |
Domain Format
Domains should be provided without protocol or path:
✅ Good:
example.comwww.example.comblog.example.com
❌ Bad:
https://example.comexample.com/example.com/blog
Timezone
Use IANA timezone identifiers:
America/New_YorkAmerica/Los_AngelesAmerica/ChicagoEurope/LondonEurope/ParisAsia/TokyoUTC
Response
{
"site": {
"id": "site_abc123",
"domain": "newsite.com",
"name": "New Site",
"timezone": "America/New_York",
"public": false,
"createdAt": "2024-12-12T16:00:00.000Z",
"trackingCode": "<script async src=\"https://cdn.ztas.io/track.js\" data-site-id=\"site_abc123\"></script>"
}
}
Important: Save the trackingCode - you’ll need to add it to your website to start collecting analytics.
Update Site
Modify site settings.
Request
curl -X PATCH "https://ztas.io/api/sites" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "site_abc123",
"name": "Updated Name",
"timezone": "America/Los_Angeles",
"public": true
}'
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Site ID to update |
name | string | No | New site name |
timezone | string | No | New timezone |
public | boolean | No | Change public visibility |
Note: You cannot change the domain after creation. Delete and recreate the site if needed.
Response
{
"site": {
"id": "site_abc123",
"domain": "example.com",
"name": "Updated Name",
"timezone": "America/Los_Angeles",
"public": true,
"updatedAt": "2024-12-12T16:00:00.000Z"
}
}
Delete Site
Delete a site (soft delete with recovery period).
Request
curl -X POST "https://ztas.io/api/sites/delete" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"siteId": "site_abc123"}'
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
siteId | string | Yes | Site ID to delete |
Response
{
"success": true,
"softDeleted": true,
"expiresAt": "2026-01-14T22:15:00.000Z",
"retentionDays": 3,
"message": "Site moved to trash. You can restore it within 3 days."
}
Recovery Window by Plan
Sites are soft-deleted and can be recovered within a plan-based retention period:
| Plan | Recovery Window |
|---|---|
| Free | 3 days |
| Starter | 7 days |
| Growth | 14 days |
| Business | 30 days |
| Scale | 30 days |
| Enterprise | 30 days |
After the recovery window expires, the site and all its data are permanently deleted.
List Deleted Sites
Get all soft-deleted sites that can still be recovered.
Request
curl "https://ztas.io/api/sites/deleted" \
-H "Authorization: Bearer YOUR_TOKEN"
Response
{
"sites": [
{
"id": "site_abc123",
"name": "Example Website",
"domain": "example.com",
"deletedAt": "2026-01-11T22:15:00.000Z",
"expiresAt": "2026-01-14T22:15:00.000Z",
"daysRemaining": 3
}
],
"count": 1
}
Restore Site
Restore a soft-deleted site before it expires.
Request
curl -X POST "https://ztas.io/api/sites/restore" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"siteId": "site_abc123"}'
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
siteId | string | Yes | Site ID to restore |
Response
{
"success": true,
"restored": true,
"site": {
"id": "site_abc123",
"name": "Example Website",
"domain": "example.com"
}
}
Error Responses
{
"error": "Site recovery period has expired"
}
{
"error": "Site not found or not deleted"
}
Get Site Details
Get detailed information about a specific site.
Request
curl "https://ztas.io/api/sites/site_abc123" \
-H "Authorization: Bearer YOUR_TOKEN"
Response
{
"site": {
"id": "site_abc123",
"domain": "example.com",
"name": "Example Website",
"timezone": "America/New_York",
"public": false,
"createdAt": "2024-01-15T10:00:00.000Z",
"owner": {
"id": "user_abc123",
"email": "owner@example.com",
"name": "Alice Johnson"
},
"stats": {
"pageviews": 125432,
"visitors": 45231,
"sessions": 67543,
"bounceRate": 42.5,
"avgSessionDuration": 185,
"lastPageview": "2024-12-12T16:30:00.000Z"
},
"team": [
{
"id": "user_abc123",
"email": "owner@example.com",
"role": "owner"
},
{
"id": "user_def456",
"email": "admin@example.com",
"role": "admin"
}
],
"goals": 5,
"funnels": 2,
"alerts": 3
}
}
Public Sites
Make your analytics data publicly viewable:
curl -X PATCH "https://ztas.io/api/sites" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "site_abc123",
"public": true
}'
When public is true:
- Anyone can view analytics at
https://ztas.io/public/site_abc123 - No authentication required
- Read-only access
- Great for open-source projects and transparency
Public dashboard URL: https://ztas.io/public/{siteId}
Tracking Code
After creating a site, add the tracking code to your website:
Standard Installation
Add before the closing </head> tag:
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
<!-- Zero Trust Analytics -->
<script async src="https://cdn.ztas.io/track.js" data-site-id="site_abc123"></script>
</head>
<body>
<!-- Your content -->
</body>
</html>
Next.js
Add to pages/_app.js or app/layout.js:
import Script from 'next/script'
export default function App({ Component, pageProps }) {
return (
<>
<Script
src="https://cdn.ztas.io/track.js"
data-site-id="site_abc123"
strategy="afterInteractive"
/>
<Component {...pageProps} />
</>
)
}
React
Add to your main component:
import { useEffect } from 'react';
function App() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://cdn.ztas.io/track.js';
script.setAttribute('data-site-id', 'site_abc123');
script.async = true;
document.head.appendChild(script);
}, []);
return <div>Your app</div>;
}
WordPress
Add to your theme’s header.php before </head>:
<script async src="https://cdn.ztas.io/track.js" data-site-id="site_abc123"></script>
<?php wp_head(); ?>
Or use the Zero Trust Analytics WordPress plugin.
Site Limits
| Plan | Max Sites |
|---|---|
| Free | 3 |
| Pro | 10 |
| Business | 50 |
| Enterprise | Unlimited |
Site Settings
Exclude Paths
Exclude certain paths from tracking:
curl -X PATCH "https://ztas.io/api/sites" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "site_abc123",
"settings": {
"excludePaths": ["/admin", "/dashboard"]
}
}'
Ignore Query Parameters
Ignore specific query parameters in URLs:
curl -X PATCH "https://ztas.io/api/sites" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "site_abc123",
"settings": {
"ignoreParams": ["utm_source", "utm_medium", "fbclid"]
}
}'
Data Retention
Configure how long to keep analytics data:
curl -X PATCH "https://ztas.io/api/sites" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "site_abc123",
"settings": {
"dataRetention": 365
}
}'
| Plan | Default Retention | Max Retention |
|---|---|---|
| Free | 90 days | 90 days |
| Pro | 1 year | 2 years |
| Business | 2 years | 5 years |
| Enterprise | 2 years | Unlimited |
Data Export
Export all site data before deleting:
curl "https://ztas.io/api/sites/site_abc123/export" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns a download URL for a ZIP file containing:
- All pageview data (CSV)
- Custom events (CSV)
- Goals and funnels (JSON)
- Site settings (JSON)
See Export API for more details.
Verify Domain Ownership
For certain features (custom domains, SSO), you may need to verify domain ownership:
curl "https://ztas.io/api/sites/site_abc123/verify" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns a TXT record to add to your DNS:
{
"verification": {
"type": "TXT",
"name": "_zta-verify",
"value": "zta-verify=abc123def456"
}
}
Add this TXT record to your DNS, then verify:
curl -X POST "https://ztas.io/api/sites/site_abc123/verify" \
-H "Authorization: Bearer YOUR_TOKEN"
Error Responses
400 Bad Request
{
"error": "Domain is required"
}
{
"error": "Invalid domain format"
}
{
"error": "Invalid timezone"
}
403 Forbidden
{
"error": "Site limit reached. Upgrade to create more sites."
}
{
"error": "Only the site owner can delete this site"
}
404 Not Found
{
"error": "Site not found"
}
409 Conflict
{
"error": "A site with this domain already exists"
}
Best Practices
1. Use Descriptive Names
Make it easy to identify sites:
✅ Good: “Marketing Website”, “Product Documentation”, “Blog” ✗ Bad: “Site 1”, “Test”, “ABC”
2. Set the Correct Timezone
Match your business timezone for accurate daily reports:
{
"timezone": "America/New_York" # If your team is in NYC
}
3. One Site Per Domain
Create separate sites for:
example.com(main site)blog.example.com(blog)app.example.com(application)
Don’t combine them into one site unless they share the same navigation.
4. Use Public Sites for Transparency
Show your metrics publicly:
{
"public": true
}
Great for:
- Open-source projects
- Transparency initiatives
- Building trust
5. Configure Exclusions Early
Exclude admin and internal pages:
{
"settings": {
"excludePaths": ["/admin", "/dashboard", "/internal"]
}
}
6. Test Tracking Before Launch
Verify tracking works:
# Send a test pageview
curl -X POST "https://ztas.io/api/track" \
-H "Content-Type: application/json" \
-d '{
"type": "pageview",
"siteId": "site_abc123",
"path": "/test"
}'
# Check realtime stats
curl "https://ztas.io/api/realtime?siteId=site_abc123" \
-H "Authorization: Bearer YOUR_TOKEN"
Example: Multi-Site Management
Manage multiple client sites:
const API_KEY = 'zta_live_abc123...';
// Create sites for all clients
const clients = [
{ domain: 'client1.com', name: 'Client 1' },
{ domain: 'client2.com', name: 'Client 2' },
{ domain: 'client3.com', name: 'Client 3' }
];
for (const client of clients) {
const response = await fetch('https://ztas.io/api/sites', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
domain: client.domain,
name: client.name,
timezone: 'America/New_York'
})
});
const data = await response.json();
console.log(`Created site for ${client.name}: ${data.site.id}`);
}
// List all sites
const sitesResponse = await fetch('https://ztas.io/api/sites', {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
const sites = await sitesResponse.json();
console.log(`Total sites: ${sites.sites.length}`);
Example: Site Backup
Backup all site configurations:
import requests
import json
API_KEY = 'zta_live_abc123...'
# Get all sites
response = requests.get(
'https://ztas.io/api/sites',
headers={'Authorization': f'Bearer {API_KEY}'}
)
sites = response.json()['sites']
# Save to file
with open('sites_backup.json', 'w') as f:
json.dump(sites, f, indent=2)
print(f"Backed up {len(sites)} sites")