Zixso for Developers
Get started
Introduction
The Zixso API provides secure, scalable access to link creation, customization, and analytics — built for developers integrating with internal tools, marketing workflows, or customer-facing apps. Each API request is scoped to an organization (called a link space in Zixso). Using service accounts tied to your link space, you can programmatically manage short links with support for custom slugs, metadata, tags, and real-time click analytics — all with minimal overhead.
Terminology
In the Zixso dashboard and user interface, we refer to your account workspace as a link space. In the API, this same concept is represented as an organization (org_id). Throughout this documentation:
- Link space = your workspace in the Zixso dashboard
- Organization (
org_id) = the same workspace when accessed via API - These terms are interchangeable and refer to the same entity
API Domain
https://api.zixso.com/
This is the root domain for all Zixso API requests. All endpoints must be prefixed with a supported version path.
API Versioning
Overview
Current Version: v0.0.1
Zixso uses URI-based versioning, where each API version is specified in the path (e.g., /v0.0.1/). This ensures that your integration remains stable and unaffected by future changes.
Versioning Policy
- Stable versions are backward-compatible within the same major version (
v1.x.x). - Breaking changes will only occur in a new major version (e.g.,
v2.0.0). - Older versions will remain available and supported until officially deprecated. Deprecation timelines will be communicated in the changelog.
- Zixso follows Semantic Versioning:
v{MAJOR}.{MINOR}.{PATCH}.
Example endpoint:
GET https://api.zixso.com/v0.0.1/orgs/{org_id}/links
Service Accounts & Credentials
Overview
To use the Zixso API, you need to authenticate every request using a Service Account — a secure identity scoped to your link space (organization).
Each service account can have one or more credentials, which are used to sign or authorize API calls.
Step 1: Create a Service Account
- Go to Settings → Service Accounts in the Zixso dashboard.
- Click + Create Account.
- Provide a label (e.g.,
Link Automation Bot). - Select a role (e.g.,
Super Administratoror a custom role). - Click Create.
Note: This service account will be scoped to your current link space, which corresponds to the org_id in API calls.
Step 2: Generate Credentials
- Open the service account you created.
- Click + Add Credential.
- Choose an Authentication Type:
- API Key – simple and fast
- HMAC – signed requests with timestamps
- Public/Private Key – cryptographic, ideal for partners
- Set a rotation period (e.g., 90 or 180 days).
- Click Create.
The secret key will only be shown once — copy and store it securely.
Authentication
Overview
Zixso supports multiple authentication methods, each using your service account credentials. Choose the method that best fits your use case.
Choosing the Right Method
| Method | Use Case |
|---|---|
| API Key | Internal tools, backend automation |
| HMAC Signature | Webhooks, secure API integrations |
| Public Key | Federated, external, or zero-trust flows |
API Key Authentication
Use Case: Internal automation or testing environments
Header Format
Authorization: APIKey <credential_id>.<token>
Example (Python):
headers = {
"Authorization": "APIKey f1e87dd7-...<truncated>...",
"Content-Type": "application/json"
}
HMAC Signature Authentication
Use Case: Server-to-server APIs or signed webhooks
Header Format
Authorization: HMAC key="<credential_id>", timestamp="<unix_timestamp>",
signature="<base64_signature>"
Message Format (for signing)
<credential_id>\n<timestamp>\n<HTTP_METHOD>\n<PATH>\n<BODY>
Example (Python):
import time, hmac, hashlib, base64
key_id = "a83e6f48-..."
secret = "your_hmac_secret"
timestamp = str(int(time.time()))
method = "POST"
path = "/v0.0.1/orgs/{org_id}/links"
body = '{"destination_url":"https://example.com"}'
message = f"{key_id}\n{timestamp}\n{method}\n{path}\n{body}"
signature = base64.b64encode(hmac.new(secret.encode(), message.encode(), hashlib.sha256).digest()).decode()
headers = {
"Authorization": f'HMAC key="{key_id}", timestamp="{timestamp}", signature="{signature}"',
"Content-Type": "application/json"
}
Public/Private Key Authentication
Zixso supports asymmetric cryptographic authentication using a private-public key pair. This method is recommended for high-trust integrations, federated services, and zero-trust environments.
Header Format
Authorization: PublicKey key="{credential_id}", timestamp="{unix_ts}",
algorithm="rsa4096", signature="{base64_signature}"
key: UUID of the public key credential (e.g.,a83e6f48-...)timestamp: Unix timestamp in seconds (±5 minutes drift allowed)algorithm: Onlyrsa4096is supported (as per current backend)signature: Base64-encoded digital signature created from request body and metadata
Message Format for Signature
The following string is constructed exactly as-is and signed with your private RSA key:
<credential_id>\n<timestamp>\n<HTTP_METHOD>\n<PATH>\n<BODY>
- No extra whitespace
- BODY must match the actual POST/PUT/PATCH payload (empty string for GET/DELETE)
PATHmust be relative (e.g.,/v0.0.1/orgs/abc123/links)
Python Example (Using cryptography)
import base64
import time
import requests
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.backends import default_backend
# Inputs
credential_id = "f8fcdc8f-db61-4bbb-94b5-4e7d65aae382"
private_key_path = "./private.pem"
timestamp = str(int(time.time()))
method = "POST"
path = "/v0.0.1/orgs/abc123/links"
body = '{"destination_url":"https://example.com"}'
# Build message
message = f"{credential_id}\n{timestamp}\n{method}\n{path}\n{body}".encode("utf-8")
# Load private key
with open(private_key_path, "rb") as key_file:
private_key = serialization.load_pem_private_key(key_file.read(), password=None)
# Sign
signature = private_key.sign(
message,
padding.PKCS1v15(),
hashes.SHA256()
)
signature_b64 = base64.b64encode(signature).decode()
# Headers
headers = {
"Authorization": (
f'PublicKey key="{credential_id}", '
f'timestamp="{timestamp}", '
f'algorithm="rsa4096", '
f'signature="{signature_b64}"'
),
"Content-Type": "application/json"
}
# Make request
response = requests.post("https://api.zixso.com" + path, data=body, headers=headers)
print(response.status_code, response.text)
Notes & Tips
- The timestamp must be within ±5 minutes of server time (
300sskew allowed) signaturemust be base64-encoded- The algorithm must be
rsa4096— other values (e.g.,rsa2048,ecdsa) will be rejected - Make sure the
bodystring is exactly what will be sent (including spaces and formatting)
API Basics
Overview
Zixso APIs follow standard REST principles with predictable resource-oriented URLs, structured JSON request/response bodies, and conventional HTTP status codes.
All APIs are versioned and accept authenticated requests scoped to a specific organization (link space).
Authentication
All requests must include a valid Authorization header using one of the supported credential types (API Key, HMAC, or Public Key).
Base URL
All API requests are made to:
https://api.zixso.com/v0.0.1/
Always include the correct version prefix (
/v0.0.1/) in your path.
Success Response Format
Most successful responses return a 2xx status code and a structured JSON body:
{
"id": "2aaf13fc-22a7-4cbb-a7f2-c1be3d9a0dd4",
"url": "https://example.com"
}
List views follow a consistent pagination structure:
{
"meta": {
"pagination": {
"page": 1,
"page_size": 10,
"no_of_records": 53
}
},
"results": [
{ ... }, { ... }
]
}
Error Response Format
All error responses follow a consistent structure:
{
"field_name": [
"This field is required."
]
}
Other examples:
{
"detail": "Authentication credentials were not provided."
}
Content-Type
All requests and responses use JSON:
Content-Type: application/json
Accept: application/json
HTTP Methods
| Method | Description |
|---|---|
GET |
Retrieve resources |
POST |
Create new resources |
PATCH |
Update partial fields |
PUT |
Replace entire object |
DELETE |
Delete a resource |
Pagination
Paginated endpoints accept:
?page=1?page_size=25
Default page_size is 10, and max allowed is 100.
Filtering & Query Parameters
Some endpoints support filtering via query parameters (e.g. ?tag=campaign, ?created_after=2025-01-01). Specific filters are documented under each endpoint.
Links API
Overview
The Links API lets you create and manage short links with advanced control — including custom aliases, expiration, password protection, redirection rules, cloaking, and tagging. All operations are scoped to your link space (org_id).
Create a Link
POST /orgs/{org_id}/links
Creates a new short link with optional customization. You can provide a custom alias, set expiration, enable cloaking, add password protection, and define redirection rules.
Request Headers
Authorization: APIKey <credential_id>.<token>
Content-Type: application/json
Request Body
{
"url": "https://www.google.com",
"alias": "link-to-google",
"label": "Google Redirect",
"tags": ["campaign", "summer"],
"password": "secret123",
"expiration_time": "2025-12-31T23:59:59Z",
"cloak": true,
"redirection_rules": [
{
"match": "AND",
"conditions": [
{ "field": "COUNTRY", "operator": "EQUAL", "value": "IN" }
],
"url": "https://www.google.co.in"
}
]
}
Response
{
"id": "4c272584-a2ad-4f1c-9996-6fc03de89d1c",
"url": "https://www.google.com",
"label": "Google Redirect",
"domain": null,
"domain_name": "127.0.0.1:8080",
"alias": "link-to-google",
"is_password_protected": true,
"expiration_time": "2025-12-31T23:59:59Z",
"cloak": true,
"redirection_rules": [
{
"match": "AND",
"conditions": [
{
"field": "COUNTRY",
"operator": "EQUAL",
"value": "IN"
}
],
"url": "https://www.google.co.in"
}
],
"tags": [
"campaign",
"summer"
],
"created_at": "2025-07-12T12:41:52.174812Z"
}
Key Notes
- If
passwordis provided,is_password_protectedwill betrue— the actual password is never returned. domainis optional; if omitted, the default domain is used.tagsmust follow the lowercase-alphanumeric-hyphen format (^[a-z0-9-]{1,30}$) and be unique.redirection_rulesmust follow strict structure and include either aurlordeeplink, not both.
List Links
GET /orgs/{org_id}/links
Retrieve all links under your link space.
Query Parameters
page=1(default:1)page_size=25(max:100)q=keyword(searches alias, domain, and back-half)
Example Response
{
"meta": {
"pagination": {
"page": 1,
"page_size": 10,
"no_of_records": 1
}
},
"results": [{
"id": "4c272584-a2ad-4f1c-9996-6fc03de89d1c",
"url": "https://www.google.com",
"label": "Homepage Redirect",
"domain": null,
"domain_name": "127.0.0.1:8080",
"alias": "link-to-google",
"is_password_protected": true,
"expiration_time": "2025-12-31T23:59:59Z",
"cloak": true,
"redirection_rules": [{
"url": "https://www.google.co.in",
"match": "AND",
"conditions": [{
"field": "COUNTRY",
"value": "IN",
"operator": "EQUAL"
}]
}],
"tags": [
"campaign",
"summer"
],
"created_at": "2025-07-12T12:41:52.174812Z"
}]
}
Get Link Details
GET /orgs/{org_id}/links/{link_id}
Retrieve full metadata, click count, tags, and rules for a specific link.
Update a Link
PATCH /orgs/{org_id}/links/{link_id}
Update one or more fields of an existing link.
Request Body
{
"url": "https://www.google.co.in",
}
Only supplied fields will be updated.
Delete a Link
DELETE /orgs/{org_id}/links/{link_id}
Deletes a link.
Returns: 204 No Content on success.
Advanced Options
Password Protection
Links can be protected with a password (min 6 characters). End-users must enter the password before redirection. Passwords are securely hashed and never stored in plain text.
Expiration
Set expires_at (ISO8601 format) to automatically deactivate a link after a specific date/time.
Cloaking
Set "cloak": true to hide the final destination from browser address bars. This is useful for embedded or promotional flows.
Redirection Rules
Control how and where users are redirected based on country.
Supported Fields
country: ISO 3166-1 alpha-2 codes (e.g.US,AE)os:Android,iOS,macOS/iPadOS,Windows,Linux
Supported Operators
EQUAL,NOT_EQUAL,IN,NOT_IN
Redirection Types
url: traditional web URLdeeplink: opens mobile app or falls back to install page
Example Rule
{
"match": "AND",
"conditions": [
{ "field": "country", "operator": "EQUAL", "value": "US" },
{ "field": "os", "operator": "IN", "value": ["iOS", "Android"] }
],
"deeplink": {
"app_link": "myapp://promo",
"install_url": "https://example.com/download"
}
}