CompactSaaS External API Reference
Complete API reference for the CompactSaaS External API. For a quick introduction, see the Getting Started Guide.
Base URLs
| Environment | Base URL |
|---|---|
| Production | https://api.compactsaas.com/v1 |
| Staging | https://api.compactsaasstaging.click/v1 |
Authentication
All endpoints except /v1/health require an API key in the x-api-key header.
API Key Format
x-api-key: pk_live_<32 random characters>
- Production keys:
pk_live_...(40 characters total) - Staging/Test keys:
pk_test_...(40 characters total)
Obtaining an API Key
- Log in to your CompactSaaS Dashboard
- Navigate to Team Settings → API Keys
- Click Create API Key
- Save the key securely (shown only once)
Key Limits
- Maximum 2 API keys per team
- Keys can be revoked immediately from the dashboard
- Revoked keys return
401 Unauthorized
Example Authenticated Request
curl -X POST https://api.compactsaas.com/v1/track \
-H "x-api-key: pk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
-H "Content-Type: application/json" \
-d '{"event": "page_view", "properties": {"page": "/home"}}'
Rate Limits
Rate limits protect the API infrastructure from abuse. They are not billing limits.
| Limit | Value | Description |
|---|---|---|
| Requests per second | 100 | Sustained request rate |
| Burst limit | 200 | Maximum burst capacity |
| Monthly quota | None | Pay-as-you-go billing |
Rate Limit Headers
When rate limited, the API returns:
- Status:
429 Too Many Requests - Header:
Retry-After: <seconds>- Time to wait before retrying
Rate Limit Response
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Please retry after the specified time.",
"code": "RATE_LIMIT_EXCEEDED"
}
Best Practices
- Implement exponential backoff for retries
- Respect the
Retry-Afterheader - Batch events when possible to reduce request count
- Monitor your request rate in the dashboard
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/track | Track an analytics event |
GET | /v1/health | Health check |
POST | /v1/links/redirects | Create a redirect |
GET | /v1/links/redirects | List redirects |
PUT | /v1/links/redirects/:id | Update a redirect |
DELETE | /v1/links/redirects/:id | Delete a redirect |
POST | /v1/links/shorten | Create a short link |
GET | /v1/links/short | List short links |
GET | /v1/links/short/:id | Get a short link |
GET | /v1/links/short/:id/stats | Get click statistics |
PUT | /v1/links/short/:id | Update a short link |
DELETE | /v1/links/short/:id | Delete a short link |
GET | /v1/links/short/:id/qr | Get QR code for a short link |
GET | /v1/links/domains | List custom domains |
POST | /v1/links/domains/fallback | Set domain fallback URL |
GET | /v1/links | List all links (unified, with search/filter/sort) |
GET | /v1/links/:id | Get a single link by ID (redirect or short link) |
For detailed Links API documentation including request/response schemas and examples, see the Links API Reference.
POST /v1/track
Track an analytics event for your application.
Request
Headers:
| Header | Required | Description |
|---|---|---|
x-api-key | Yes | Your API key |
Content-Type | Yes | Must be application/json |
Body:
{
"event": "string (required)",
"properties": "object (optional)",
"timestamp": "ISO 8601 string (optional)"
}
| Field | Type | Required | Description |
|---|---|---|---|
event | string | Yes | Event name (1-255 characters). Use descriptive names like page_view, button_click, purchase_completed. |
properties | object | No | Key-value pairs with additional event data. Values can be strings, numbers, booleans, or nested objects. |
timestamp | string | No | ISO 8601 timestamp for when the event occurred. Defaults to server time if not provided. |
Response
Success (202 Accepted):
{
"success": true
}
The 202 Accepted status indicates the event was received and queued for asynchronous processing.
Examples
Track a page view:
curl -X POST https://api.compactsaas.com/v1/track \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"event": "page_view",
"properties": {
"page": "/pricing",
"referrer": "https://google.com"
}
}'
Track a button click:
curl -X POST https://api.compactsaas.com/v1/track \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"event": "button_click",
"properties": {
"button_id": "signup_cta",
"button_text": "Get Started"
}
}'
Track a purchase with timestamp:
curl -X POST https://api.compactsaas.com/v1/track \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"event": "purchase_completed",
"properties": {
"product_id": "prod_123",
"amount": 99.99,
"currency": "USD"
},
"timestamp": "2024-01-15T10:30:00Z"
}'
Billing
Each call to /v1/track is counted as one API call for billing purposes. Usage is aggregated hourly and appears on your monthly Stripe invoice.
Tenant Isolation
Events are automatically associated with your team based on the API key used. You cannot specify a different team ID in the request body—tenant identification is handled securely by the API key authorizer.
GET /v1/health
Health check endpoint for monitoring and uptime checks.
Request
Headers: None required (no authentication)
Response
Success (200 OK):
{
"status": "ok",
"timestamp": "2024-01-15T10:30:00.000Z",
"version": "v1"
}
| Field | Type | Description |
|---|---|---|
status | string | Always "ok" when healthy |
timestamp | string | Current server timestamp (ISO 8601) |
version | string | API version ("v1") |
Example
curl https://api.compactsaas.com/v1/health
Response:
{
"status": "ok",
"timestamp": "2024-01-15T10:30:00.000Z",
"version": "v1"
}
Use Cases
- Uptime monitoring (e.g., Pingdom, UptimeRobot)
- Load balancer health checks
- Pre-flight checks before sending events
Links API
The Links API provides URL redirect management, short link generation, and custom domain configuration. All links endpoints are under the /v1/links/ prefix.
Key Features
- Redirects — Route traffic from one domain/path to another with 301/302 redirects served at the edge (sub-millisecond)
- Short Links — Generate compact URLs on the platform's short domain with auto-generated or custom codes
- Click Analytics — Enable
analyticsEnabledon any link to track clicks as pageviews in your analytics dashboard, billed via theadvanced_analytics_pageviewsmeter - Custom Domains — Serve redirects from your own domain with managed TLS certificates
Quick Example
# Create a short link with analytics
curl -X POST https://api.compactsaas.com/v1/links/shorten \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"targetUrl": "https://example.com/campaign", "analyticsEnabled": true}'
{
"link": {
"id": "01KK6MCSFTTM0GPJB3XEBWJACY",
"shortCode": "oTmGvkP",
"shortUrl": "https://urlz.zip/oTmGvkP",
"targetUrl": "https://example.com/campaign",
"analyticsEnabled": true,
"analyticsWebsiteId": "01KK6MD0A1B2C3D4E5F6G7H8J9",
"hasClicks": true
}
}
# Get a single short link
curl https://api.compactsaas.com/v1/links/short/01KK6MCSFTTM0GPJB3XEBWJACY \
-H "x-api-key: pk_live_your_key_here"
{
"link": {
"id": "01KK6MCSFTTM0GPJB3XEBWJACY",
"shortCode": "oTmGvkP",
"shortUrl": "https://urlz.zip/oTmGvkP",
"targetUrl": "https://example.com/campaign",
"domain": "urlz.zip",
"enabled": true,
"analyticsEnabled": true,
"analyticsWebsiteId": "01KK6MD0A1B2C3D4E5F6G7H8J9",
"hasClicks": true,
"createdAt": 1773056521115,
"updatedAt": 1773056521115
}
}
# Get click statistics (last 14 days)
curl "https://api.compactsaas.com/v1/links/short/01KK6MCSFTTM0GPJB3XEBWJACY/stats?days=14" \
-H "x-api-key: pk_live_your_key_here"
{
"linkId": "01KK6MCSFTTM0GPJB3XEBWJACY",
"totalClicks": 42,
"days": 14,
"timeseries": [
{ "date": "2026-03-08", "clicks": 3 },
{ "date": "2026-03-09", "clicks": 5 },
{ "date": "2026-03-15", "clicks": 10 },
{ "date": "2026-03-16", "clicks": 24 }
]
}
For the complete Links API reference with all endpoints, request/response schemas, and examples, see the Links API Reference.
Unified Links
# List all links (both redirects and short links)
curl "https://api.compactsaas.com/v1/links?type=shortlink&search=example&sort=created&order=desc" \
-H "x-api-key: pk_live_your_key_here"
// Response
{
"links": [
{
"id": "01KK6MCSFTTM0GPJB3XEBWJACY",
"type": "shortlink",
"sourceUrl": "s.urlz.zip/abc123",
"shortCode": "abc123",
"shortUrl": "s.urlz.zip/abc123",
"targetUrl": "https://example.com",
"domain": "s.urlz.zip",
"enabled": true,
"analyticsEnabled": true,
"analyticsWebsiteId": "01KKPHGQRZRG6PQGHPCG69GZDS",
"hasClicks": true,
"createdAt": "2026-03-15T10:00:00.000Z",
"updatedAt": "2026-03-15T10:00:00.000Z"
}
]
}
# Get a single link by ID (works for both redirects and short links)
curl https://api.compactsaas.com/v1/links/01KK6MCSFTTM0GPJB3XEBWJACY \
-H "x-api-key: pk_live_your_key_here"
// Response
{
"link": {
"id": "01KK6MCSFTTM0GPJB3XEBWJACY",
"type": "shortlink",
"sourceUrl": "s.urlz.zip/abc123",
"shortCode": "abc123",
"targetUrl": "https://example.com",
"enabled": true,
"analyticsEnabled": true,
"createdAt": "2026-03-15T10:00:00.000Z",
"updatedAt": "2026-03-15T10:00:00.000Z"
}
}
Bio Pages API
The Bio Pages API lets you create and manage link-in-bio pages programmatically. Each bio page gets a tracked short link, full analytics, and a public URL. All endpoints are under the /v1/bio/ prefix.
Key Features
- Themed Pages — Customize colors, button styles, fonts, and social icons
- Link Management — Add existing short links to your bio page with drag-to-reorder
- Analytics — Every page view and link click tracked through the analytics pipeline
- Social Sharing — OG meta tags served to social media crawlers for rich previews
- Avatar Images — Upload profile images stored in S3 with presigned URLs
Quick Example
# Create a bio page
curl -X POST https://api.compactsaas.com/v1/bio \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"title": "My Links", "bio": "Developer & creator", "published": true}'
# Response
# {"bioPage": {"id": "01J...", "title": "My Links", "shortUrl": "https://staging.urlz.zip/abc123", ...}}
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /v1/bio | Create a bio page |
GET | /v1/bio | List all bio pages |
GET | /v1/bio/:pageId | Get a bio page |
PUT | /v1/bio/:pageId | Update a bio page |
DELETE | /v1/bio/:pageId | Delete a bio page |
Create/Update Fields
| Field | Type | Description |
|---|---|---|
title | string | Page title (required on create, max 200 chars) |
bio | string | Bio text (max 2000 chars) |
published | boolean | Whether the page is publicly visible |
links | array | Ordered list of {shortLinkId, title, visible} |
socialLinks | array | List of {platform, url} — platforms: twitter, instagram, tiktok, youtube, linkedin, github, facebook, website |
theme | object | {bgColor, textColor, buttonColor, buttonTextColor, buttonBorderRadius, buttonStyle, fontFamily} |
Error Responses
All error responses follow a consistent format:
{
"error": "Error Type",
"message": "Human-readable description",
"code": "MACHINE_READABLE_CODE"
}
Error Codes Reference
| HTTP Status | Error Code | Description | Common Causes |
|---|---|---|---|
| 400 | VALIDATION_ERROR | Invalid request body | Missing event field, invalid JSON, invalid timestamp format |
| 401 | UNAUTHORIZED | Authentication failed | Missing API key, invalid API key, revoked API key |
| 403 | ACCOUNT_DISABLED | Account access denied | Account disabled, suspended, or payment failed |
| 404 | NOT_FOUND | Endpoint not found | Invalid URL path |
| 429 | RATE_LIMIT_EXCEEDED | Rate limit exceeded | Too many requests per second |
| 500 | INTERNAL_ERROR | Server error | Unexpected server-side error |
Detailed Error Examples
400 Bad Request - Missing Event Name
{
"error": "Validation error",
"message": "Event name is required",
"code": "VALIDATION_ERROR"
}
Cause: The event field is missing or empty in the request body.
Solution: Include a valid event name in your request:
{
"event": "page_view",
"properties": {}
}
400 Bad Request - Invalid Timestamp
{
"error": "Validation error",
"message": "Invalid datetime format for timestamp",
"code": "VALIDATION_ERROR"
}
Cause: The timestamp field is not a valid ISO 8601 string.
Solution: Use ISO 8601 format: 2024-01-15T10:30:00Z
401 Unauthorized - Invalid API Key
{
"error": "Unauthorized",
"message": "Invalid or missing API key",
"code": "UNAUTHORIZED"
}
Cause:
- API key is missing from the
x-api-keyheader - API key is invalid or malformed
- API key has been revoked
Solution:
- Verify the
x-api-keyheader is included - Check that the key matches the format
pk_live_...orpk_test_... - Verify the key hasn't been revoked in the dashboard
403 Forbidden - Account Disabled
{
"error": "Forbidden",
"message": "Account is disabled. Please contact support.",
"code": "ACCOUNT_DISABLED"
}
Cause:
- Account has been disabled by an administrator
- Subscription has been cancelled
- Payment has failed
Solution:
- Check your account status in the dashboard
- Verify your payment method is up to date
- Contact support if the issue persists
429 Too Many Requests - Rate Limited
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Please retry after the specified time.",
"code": "RATE_LIMIT_EXCEEDED"
}
Headers:
Retry-After: 60
Cause: You've exceeded the rate limit of 100 requests per second.
Solution:
- Wait for the duration specified in the
Retry-Afterheader - Implement exponential backoff in your retry logic
- Consider batching events to reduce request frequency
500 Internal Server Error
{
"error": "Internal Server Error",
"message": "An unexpected error occurred",
"code": "INTERNAL_ERROR"
}
Cause: An unexpected error occurred on the server.
Solution:
- Retry the request with exponential backoff
- Check the status page for incidents
- Contact support if the issue persists
Request/Response Schemas
TrackEventRequest
interface TrackEventRequest {
// Required: Name of the event (1-255 characters)
event: string;
// Optional: Additional event properties
properties?: Record<string, any>;
// Optional: ISO 8601 timestamp (defaults to server time)
timestamp?: string;
}
TrackEventResponse
interface TrackEventResponse {
success: boolean;
}
HealthResponse
interface HealthResponse {
status: "ok";
timestamp: string; // ISO 8601 format
version: string; // e.g., "v1"
}
ErrorResponse
interface ErrorResponse {
error: string; // Error type
message: string; // Human-readable description
code: ErrorCode; // Machine-readable code
}
type ErrorCode =
| "VALIDATION_ERROR"
| "UNAUTHORIZED"
| "ACCOUNT_DISABLED"
| "RATE_LIMIT_EXCEEDED"
| "INTERNAL_ERROR"
| "NOT_FOUND";
Billing
Pay-As-You-Go Model
CompactSaaS uses a simple pay-as-you-go billing model:
- No monthly quotas - Use as much as you need
- No tiers - Same rate for all customers
- Transparent pricing - See current rates in your dashboard
How Billing Works
- Each API call to
/v1/trackis counted - Usage is aggregated hourly
- Usage is reported to Stripe Billing Meters
- All API calls appear on your monthly Stripe invoice
Viewing Usage
- Log in to your CompactSaaS Dashboard
- Navigate to Billing → Usage
- View current billing period usage and estimated cost
Billing vs Rate Limits
| Aspect | Rate Limits | Billing |
|---|---|---|
| Purpose | DDoS protection | Usage tracking |
| Limit type | Requests per second | None (pay-as-you-go) |
| Enforcement | 429 response | Monthly invoice |
| Configurable | No | Pricing in dashboard |
Security
API Key Security
- API keys are hashed (SHA-256) before storage
- Full keys are shown only once at creation
- Keys can be revoked immediately
- Revoked keys are disabled in real-time
Tenant Isolation
- Tenant identification comes from the API key, not request body
- All data operations are scoped to your team
- Cross-tenant access is prevented at the data layer
Transport Security
- All API traffic uses HTTPS (TLS 1.2+)
- HTTP requests are rejected
WAF Protection
- AWS WAF protects against common attacks
- IP-based rate limiting (10,000 requests per 5 minutes per IP)
- AWS Managed Rules for common vulnerabilities
Best Practices
Event Naming
Use consistent, descriptive event names:
Good: page_view, button_click, purchase_completed, user_signup
Bad: event1, click, e, pv
Properties
Include relevant context in properties:
{
"event": "purchase_completed",
"properties": {
"product_id": "prod_123",
"product_name": "Pro Plan",
"amount": 99.99,
"currency": "USD",
"payment_method": "card"
}
}
Error Handling
Implement robust error handling:
async function trackEvent(event, properties) {
try {
const response = await fetch('https://api.compactsaas.com/v1/track', {
method: 'POST',
headers: {
'x-api-key': API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({ event, properties }),
});
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
// Wait and retry
}
if (!response.ok) {
const error = await response.json();
console.error(`API error: ${error.code} - ${error.message}`);
}
return response.json();
} catch (error) {
console.error('Network error:', error);
// Queue for retry
}
}
Retry Strategy
Use exponential backoff for retries:
async function trackWithRetry(event, properties, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await trackEvent(event, properties);
return response;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
Related Documentation
- Getting Started Guide - Quick introduction and setup
- Links API Reference - Complete redirect, short link, and domain management reference
- SDK Code Snippets - Code examples for common languages
- OpenAPI Specification - Import into Postman, Swagger UI, etc.
Support
- Dashboard: View usage, manage keys, and access support
- Email: support@compactsaas.com
- Status Page: status.compactsaas.com
Changelog
v1.3.0
- Bio Pages:
POST /v1/bio— create a link-in-bio page - Bio Pages:
GET /v1/bio— list bio pages - Bio Pages:
GET /v1/bio/:pageId— get bio page details - Bio Pages:
PUT /v1/bio/:pageId— update bio page - Bio Pages:
DELETE /v1/bio/:pageId— delete bio page - QR Codes: Added API Gateway routes for
/v1/qr/*endpoints (previously missing)
v1.2.0
- Unified links:
GET /v1/links— list all links with search, filter, sort - Unified links:
GET /v1/links/:id— get any link by ID (redirect or short link)
v1.1.0
- Links API: Redirects CRUD (
/v1/links/redirects) - Links API: Short Links CRUD (
/v1/links/shorten,/v1/links/short) - Links API: Custom Domains (
/v1/links/domains) - Click analytics:
analyticsEnabledfield on redirects and short links - Analytics dashboard: Websites, Links, and Redirects tabs
v1.0.0
- Initial release
POST /v1/track- Analytics event trackingGET /v1/health- Health check endpoint- API key authentication
- Pay-as-you-go billing via Stripe