CompactSaaS Links API Reference
Complete API reference for the CompactSaaS Links service. The Links API provides URL redirect management, short link generation, and custom domain configuration with managed TLS.
Base URL
The Links API is available through the CompactSaaS External API, the same endpoint used for analytics tracking.
| Environment | Base URL |
|---|---|
| Production | https://api.compactsaas.com/v1 |
| Staging | https://api.compactsaasstaging.click/v1 |
All endpoints are under the /v1/links/ prefix. The team is identified automatically from your API key — no team ID in the URL.
Authentication
All endpoints require an API key in the x-api-key header.
x-api-key: pk_live_<32 random characters>
API keys can be created from the CompactSaaS dashboard under API Keys in the sidebar. Each key is bound to a team — all operations are scoped to that team automatically.
Error Responses
| Status | Body | Cause |
|---|---|---|
401 | {"message": "Unauthorized"} | Missing, invalid, or revoked API key |
403 | {"message": "Forbidden"} | Account disabled or suspended |
Error Format
The API returns errors in two formats depending on the error type:
Validation Errors (request schema violations)
{
"errors": [
{ "param": "sourceDomain", "type": "String must contain at least 1 character(s)" },
{ "param": "targetUrl", "type": "Invalid url" }
]
}
Business Logic Errors
{
"errors": "validation_error"
}
Common error codes:
| Code | HTTP Status | Description |
|---|---|---|
validation_error | 400 | Business rule violation (e.g., unverified domain, duplicate redirect) |
not_found | 404 | Resource does not exist |
unauthorized | 401 | Authentication required |
not_member | 403 | User is not a team member |
internal_server_error | 500 | Unexpected server error |
Timestamps
All timestamp fields (createdAt, updatedAt, verifiedAt) are Unix epoch milliseconds (e.g., 1772970450599).
Redirects
Redirects map a source domain + path to a target URL. When a request hits the CloudFront edge network matching {sourceDomain}{sourcePath}, it returns an HTTP redirect (301 or 302) to the targetUrl.
Redirects are served at the edge via CloudFront Functions backed by a Key-Value Store (KVS), so they execute in under 1ms with no origin round-trip.
Create Redirect
Creates a new redirect rule and immediately syncs it to the edge network.
POST /v1/links/redirects
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
sourceDomain | string | Yes | — | The domain to match. Must be a platform domain (e.g., links.compactsaasstaging.click) or a verified custom domain. Min 1, max 253 characters. |
sourcePath | string | No | "/" | The URL path to match. Must start with /. Min 1, max 2048 characters. |
targetUrl | string | Yes | — | The destination URL. Must be a valid URL. Max 2048 characters. |
statusCode | integer | No | 301 | HTTP redirect status code. Must be 301 (Moved Permanently) or 302 (Found). |
ttl | integer | No | 86400 | Cache TTL in seconds for the redirect response at the edge. Min 0, max 31536000 (1 year). |
analyticsEnabled | boolean | No | false | Enable click analytics. When enabled, clicks are tracked as pageviews in the analytics dashboard and billed via the advanced_analytics_pageviews meter. |
Example Request
curl -X POST https://api.compactsaas.com/v1/links/redirects \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"sourceDomain": "links.genairumors.com",
"sourcePath": "/hello",
"targetUrl": "https://compactsaas.com",
"statusCode": 301,
"ttl": 86400
}'
Response — 201 Created
{
"redirect": {
"id": "01KK6MC7N71NTJ7XHJKRMR119V",
"sourceDomain": "links.compactsaasstaging.click",
"sourcePath": "/doc-test",
"targetUrl": "https://example.com/doc-test",
"statusCode": 302,
"ttl": 3600,
"enabled": true,
"analyticsEnabled": false,
"analyticsWebsiteId": null,
"createdAt": 1772970450599,
"updatedAt": 1772970450599
}
}
Errors
| Status | Code | Cause |
|---|---|---|
400 | validation_error | sourceDomain is not a platform domain and is not verified for this team |
400 | validation_error | A redirect already exists for this sourceDomain + sourcePath combination |
400 | (array) | Request body fails schema validation |
List Redirects
Returns all redirects for the team.
GET /v1/links/redirects
Example Request
curl https://api.compactsaas.com/v1/links/redirects \
-H "x-api-key: pk_live_your_key_here"
Response — 200 OK
{
"redirects": [
{
"id": "01KK6E10671WWMNV9RWA2ZKGQE",
"sourceDomain": "links.genairumors.com",
"sourcePath": "/hello",
"targetUrl": "https://compactsaas.com",
"statusCode": 301,
"ttl": 86400,
"enabled": true,
"analyticsEnabled": false,
"analyticsWebsiteId": null,
"createdAt": 1772963791047,
"updatedAt": 1772963791047
}
]
}
Returns an empty array if no redirects exist: {"redirects": []}.
Update Redirect
Updates an existing redirect. Only the fields provided in the request body are changed. The edge KVS entry is re-synced immediately.
PUT /v1/links/redirects/{redirectId}
Path Parameters
| Parameter | Description |
|---|---|
redirectId | The redirect's id field (ULID) |
Request Body
All fields are optional. Only provided fields are updated.
| Field | Type | Description |
|---|---|---|
targetUrl | string | New destination URL. Must be a valid URL. Max 2048 characters. |
statusCode | integer | New HTTP status code. Must be 301 or 302. |
ttl | integer | New cache TTL in seconds. Min 0, max 31536000. |
enabled | boolean | Enable or disable the redirect. Disabled redirects are removed from the edge. |
analyticsEnabled | boolean | Enable or disable click analytics. |
Example Request
curl -X PUT https://api.compactsaas.com/v1/links/redirects/01KK6MC7N71NTJ7XHJKRMR119V \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"targetUrl": "https://example.com/updated", "statusCode": 301}'
Response — 200 OK
{
"redirect": {
"id": "01KK6MC7N71NTJ7XHJKRMR119V",
"sourceDomain": "links.compactsaasstaging.click",
"sourcePath": "/doc-test",
"targetUrl": "https://example.com/updated",
"statusCode": 301,
"ttl": 3600,
"enabled": true,
"analyticsEnabled": false,
"analyticsWebsiteId": null,
"createdAt": 1772970450599,
"updatedAt": 1772970467719
}
}
Errors
| Status | Code | Cause |
|---|---|---|
404 | not_found | Redirect does not exist or does not belong to this team |
Delete Redirect
Permanently deletes a redirect and removes it from the edge KVS.
DELETE /v1/links/redirects/{redirectId}
Example Request
curl -X DELETE https://api.compactsaas.com/v1/links/redirects/01KK6MC7N71NTJ7XHJKRMR119V \
-H "x-api-key: pk_live_your_key_here"
Response — 204 No Content
Empty response body.
Errors
| Status | Code | Cause |
|---|---|---|
404 | not_found | Redirect does not exist or does not belong to this team |
Short Links
Short links generate a compact URL on the platform's short domain (e.g., staging.urlz.zip in staging, urlz.zip in production). Each short link gets a unique 7-character base62 code, or you can specify a custom code.
Short links are served at the edge identically to redirects — via CloudFront Functions and KVS.
Create Short Link
Creates a new short link with either an auto-generated or custom short code.
POST /v1/links/shorten
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
targetUrl | string | Yes | The destination URL. Must be a valid URL. Max 2048 characters. |
customCode | string | No | Custom short code. 3–32 characters, alphanumeric plus - and _ only (/^[a-zA-Z0-9_-]+$/). If omitted, a random 7-character base62 code is generated. |
domain | string | No | Custom domain for the short link. Must be a verified and active custom domain for your team. If omitted, uses the platform default domain (urlz.zip). |
analyticsEnabled | boolean | No | Enable click analytics. When enabled, clicks are tracked as pageviews in the analytics dashboard. |
Example Request — Auto-generated Code
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/my-long-page"}'
Response — 201 Created
{
"link": {
"id": "01KK6MCSFTTM0GPJB3XEBWJACY",
"shortCode": "oTmGvkP",
"shortUrl": "https://staging.urlz.zip/oTmGvkP",
"targetUrl": "https://example.com/short-test",
"domain": "staging.urlz.zip",
"enabled": true,
"analyticsEnabled": false,
"analyticsWebsiteId": null,
"hasClicks": false,
"createdAt": 1772970468859,
"updatedAt": 1772970468859
}
}
Example Request — Custom Code
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/promo", "customCode": "summer-sale"}'
Response — 201 Created
{
"link": {
"id": "01KK6MCT06Q29ZSQAXT4RSK3P4",
"shortCode": "summer-sale",
"shortUrl": "https://staging.urlz.zip/summer-sale",
"targetUrl": "https://example.com/promo",
"domain": "staging.urlz.zip",
"enabled": true,
"analyticsEnabled": false,
"analyticsWebsiteId": null,
"hasClicks": false,
"createdAt": 1772970469382,
"updatedAt": 1772970469382
}
}
Errors
| Status | Code | Cause |
|---|---|---|
400 | validation_error | Custom code already in use |
400 | (array) | Request body fails schema validation |
List Short Links
Returns all short links for the team.
GET /v1/links/short
Example Request
curl https://api.compactsaas.com/v1/links/short \
-H "x-api-key: pk_live_your_key_here"
Response — 200 OK
{
"links": [
{
"id": "01KK6MCSFTTM0GPJB3XEBWJACY",
"shortCode": "oTmGvkP",
"shortUrl": "https://staging.urlz.zip/oTmGvkP",
"targetUrl": "https://example.com/short-test",
"domain": "staging.urlz.zip",
"enabled": true,
"analyticsEnabled": false,
"analyticsWebsiteId": null,
"hasClicks": false,
"createdAt": 1772970468859,
"updatedAt": 1772970468859
}
]
}
Returns an empty array if no short links exist: {"links": []}.
Get Short Link
Returns a single short link by ID.
GET /v1/links/short/{linkId}
Path Parameters
| Parameter | Description |
|---|---|
linkId | The short link's id field (ULID) |
Example Request
curl https://api.compactsaas.com/v1/links/short/01KK6MCSFTTM0GPJB3XEBWJACY \
-H "x-api-key: pk_live_your_key_here"
Response — 200 OK
{
"link": {
"id": "01KK6MCSFTTM0GPJB3XEBWJACY",
"shortCode": "oTmGvkP",
"shortUrl": "https://staging.urlz.zip/oTmGvkP",
"targetUrl": "https://example.com/short-test",
"domain": "staging.urlz.zip",
"enabled": true,
"analyticsEnabled": false,
"analyticsWebsiteId": null,
"hasClicks": false,
"createdAt": 1772970468859,
"updatedAt": 1772970468859
}
}
Returns 404 NOT_FOUND if the link does not exist.
Get Short Link Stats
Returns daily click timeseries data for a short link. Data comes from analytics rollups which are preserved permanently, regardless of the raw event retention policy. Requires analyticsEnabled on the link.
GET /v1/links/short/{linkId}/stats
Path Parameters
| Parameter | Description |
|---|---|
linkId | The short link's id field (ULID) |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
days | integer | 30 | Trailing days to include (1–730) |
Example Request
curl "https://api.compactsaas.com/v1/links/short/01KK6MCSFTTM0GPJB3XEBWJACY/stats?days=14" \
-H "x-api-key: pk_live_your_key_here"
Response — 200 OK
{
"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 }
]
}
Returns 404 NOT_FOUND if the link does not exist. Returns totalClicks: 0 and empty timeseries if analytics is not enabled on the link or the analytics table is unavailable.
Update Short Link
Updates an existing short link. Only the fields provided in the request body are changed. If targetUrl is changed, the edge KVS entry is re-synced immediately.
PUT /v1/links/short/{linkId}
Path Parameters
| Parameter | Description |
|---|---|
linkId | The short link's id field (ULID) |
Request Body
All fields are optional. Only provided fields are updated.
| Field | Type | Description |
|---|---|---|
targetUrl | string | New destination URL. Must be a valid URL. Max 2048 characters. |
analyticsEnabled | boolean | Enable or disable click analytics. |
Example Request
curl -X PUT https://api.compactsaas.com/v1/links/short/01KK6MCSFTTM0GPJB3XEBWJACY \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"analyticsEnabled": true}'
Response — 200 OK
{
"link": {
"id": "01KK6MCSFTTM0GPJB3XEBWJACY",
"shortCode": "oTmGvkP",
"shortUrl": "https://staging.urlz.zip/oTmGvkP",
"targetUrl": "https://example.com/short-test",
"domain": "staging.urlz.zip",
"enabled": true,
"analyticsEnabled": true,
"analyticsWebsiteId": "01KK6MD0A1B2C3D4E5F6G7H8J9",
"hasClicks": true,
"createdAt": 1772970468859,
"updatedAt": 1772970512000
}
}
Errors
| Status | Code | Cause |
|---|---|---|
404 | not_found | Short link does not exist or does not belong to this team |
Delete Short Link
Permanently deletes a short link and removes it from the edge KVS.
DELETE /v1/links/short/{linkId}
Path Parameters
| Parameter | Description |
|---|---|
linkId | The short link's id field (ULID) |
Example Request
curl -X DELETE https://api.compactsaas.com/v1/links/short/01KK6MCSFTTM0GPJB3XEBWJACY \
-H "x-api-key: pk_live_your_key_here"
Response — 204 No Content
Empty response body.
Get QR Code
Generate a QR code for a short link. Returns the QR code image directly (not JSON). The response is cacheable — identical requests return the same image.
Every short link automatically has a QR code endpoint. No creation limits, no branding restrictions.
GET /v1/links/short/{linkId}/qr
Path Parameters
| Parameter | Description |
|---|---|
linkId | The short link's id field (ULID) |
Query Parameters
All query parameters are optional.
| Parameter | Type | Default | Description |
|---|---|---|---|
format | svg | png | svg | Image format. SVG is ~1.5KB, PNG is ~2KB at 300px |
size | 100–1000 | 300 | Image dimensions in pixels |
color | hex color | #000000 | QR code foreground color |
bgColor | hex color | #ffffff | QR code background color |
Example Request — Default SVG
curl https://api.compactsaas.com/v1/links/short/01KK6MCSFTTM0GPJB3XEBWJACY/qr \
-H "x-api-key: pk_live_your_key_here" \
-o qr-code.svg
Example Request — Custom Branded PNG
curl "https://api.compactsaas.com/v1/links/short/01KK6MCSFTTM0GPJB3XEBWJACY/qr?format=png&size=500&color=%23FF6600&bgColor=%23FFFFFF" \
-H "x-api-key: pk_live_your_key_here" \
-o qr-code.png
Response
Returns the image directly with appropriate Content-Type header:
- SVG:
Content-Type: image/svg+xml - PNG:
Content-Type: image/png
Response includes Cache-Control: public, max-age=86400 for edge caching.
QR Code Analytics
When a short link has analyticsEnabled: true, every QR code scan is automatically tracked in your analytics dashboard. QR scans appear as "Direct / QR" traffic — distinguishable from regular link clicks which show the referring page.
No additional setup required. Create a short link with analytics enabled, download the QR code, and every scan shows up alongside your website traffic.
Errors
| Status | Error | Cause |
|---|---|---|
404 | Short link not found | Invalid linkId or link belongs to another team |
Custom Domains
Custom domains allow your team to serve redirects from your own domain (e.g., links.yourcompany.com) with fully managed TLS certificates.
Domain setup (verification, activation, TLS provisioning) is done through the CompactSaaS dashboard. Once a domain is active, you can manage it programmatically via this API:
- List domains — see all your custom domains and their status
- Set fallback URL — configure where unmatched paths redirect to (instead of 403)
Domain Lifecycle
Dashboard: Verify → Check DNS → Activate → Wait for TLS → Active
API: List domains (read-only) | Set fallback URL (active domains only)
Set Domain Fallback URL
Configures a fallback redirect URL for a custom domain. When a request arrives at your custom domain for a path that has no matching redirect rule, the fallback URL is used instead of returning a raw 403 error from the origin.
The fallback is served as a 302 Found redirect at the edge.
The domain must have tenantStatus: "active".
POST /v1/links/domains/fallback
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
domain | string | Yes | The active custom domain. |
fallbackUrl | string | Yes | The URL to redirect unmatched paths to. Must be a valid URL. Send an empty string "" or null to clear the fallback. |
Example Request — Set Fallback
curl -X POST https://api.compactsaas.com/v1/links/domains/fallback \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"domain": "links.yourcompany.com", "fallbackUrl": "https://yourcompany.com"}'
Response — 200 OK
{
"domain": {
"domain": "links.yourcompany.com",
"status": "verified",
"tenantStatus": "active",
"fallbackUrl": "https://yourcompany.com",
"verifiedAt": 1772836089453,
"createdAt": 1772836027575
}
}
Example Request — Clear Fallback
curl -X POST https://api.compactsaas.com/v1/links/domains/fallback \
-H "x-api-key: pk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{"domain": "links.yourcompany.com", "fallbackUrl": ""}'
Errors
| Status | Code | Cause |
|---|---|---|
404 | not_found | No verification record exists for this domain and team |
400 | validation_error | Domain is not yet active (tenantStatus must be "active") |
List Domain Verifications
Returns all domain verification records for the team, including their current status and tenant information.
GET /v1/links/domains
Example Request
curl https://api.compactsaas.com/v1/links/domains \
-H "x-api-key: pk_live_your_key_here"
Response — 200 OK
{
"domains": [
{
"domain": "links.genairumors.com",
"status": "verified",
"tenantStatus": "active",
"fallbackUrl": "https://genairumors.com",
"verifiedAt": 1772836089453,
"createdAt": 1772836027575
}
]
}
Returns an empty array if no domains are configured: {"domains": []}.
Domain Object
| Field | Type | Description |
|---|---|---|
domain | string | The custom domain name. |
status | string | DNS verification status: "pending", "verified", or "failed". |
tenantStatus | string | null | Tenant provisioning status: "creating", "active", "failed", or null. |
fallbackUrl | string | null | Fallback redirect URL for unmatched paths. null if not configured. |
verifiedAt | number | null | Timestamp (ms) when DNS was verified. null if not yet verified. |
createdAt | number | Timestamp (ms) when the record was created. |
API Endpoint Summary
| Method | Endpoint | Description |
|---|---|---|
POST | /v1/links/redirects | Create a redirect |
GET | /v1/links/redirects | List all redirects |
PUT | /v1/links/redirects/{redirectId} | Update a redirect |
DELETE | /v1/links/redirects/{redirectId} | Delete a redirect |
POST | /v1/links/shorten | Create a short link |
GET | /v1/links/short | List all short links |
DELETE | /v1/links/short/{linkId} | Delete a short link |
GET | /v1/links/domains | List custom domains |
POST | /v1/links/domains/fallback | Set/clear fallback URL |
Domain setup (verification, activation, TLS provisioning) is managed through the CompactSaaS dashboard.
Dashboard API — Unified Links
These endpoints are used by the CompactSaaS dashboard (Cognito JWT auth, not API key auth). They provide a unified view across both redirects and short links.
List All Links
GET /:teamId/links/all
Returns both redirects and short links in a single array. Each item has a type field ("redirect" or "shortlink") and a sourceUrl field.
Query Parameters:
| Param | Type | Description |
|---|---|---|
type | redirect | shortlink | Filter by link type |
search | string | Case-insensitive substring match on sourceUrl, targetUrl, or shortCode |
sort | created | updated | Sort field (default: created) |
order | asc | desc | Sort order (default: desc) |
Get Link Detail
GET /:teamId/links/detail/:linkId
Returns a single link by ID. Tries short link first, then redirect (two point Gets, no scan). Returns 404 if neither exists.
Response includes all fields for the link type plus type and sourceUrl.
List All Links (External API)
GET /v1/links
Same as the dashboard GET /:teamId/links/all but uses API key auth. Team is determined from the API key.
Query Parameters: Same as dashboard — type, search, sort, order.
Get Link Detail (External API)
GET /v1/links/:linkId
Same as the dashboard GET /:teamId/links/detail/:linkId but uses API key auth. Returns 404 if neither a short link nor redirect exists with the given ID.