API Reference
Full REST API for link management, analytics, webhooks, and account configuration. Includes the legacy XML/simple-text API for existing integrations.
Authentication
Two methods. JWT is preferred for new integrations. API key is the legacy method and is supported everywhere.
Exchange email + password for a 7-day JWT. Pass it as Authorization: Bearer <token> on all subsequent requests.
/api/auth/jwt
{ "email": "you@example.com", "password": "secret" }
→ { "token": "eyJ..." }
Token payload: { userId, accountId }. Account context is fixed at issuance time to the domain used for login.
Append ?apiKey=<key> to any request. Find your key at Settings → Security → API Key.
GET /api/links?apiKey=abc123...
API keys are SHA1 hex strings. Regenerating invalidates the old key immediately.
Base URL & Response Formats
All REST endpoints return JSON. The legacy API supports XML (default), JSON, and plain-text.
REST API base: https://app.shortswitch.com
Content-Type: application/json for all request bodies.
Legacy format selection: append ?format=json, ?format=xml, or ?format=simple. Default is xml.
Error Handling
REST API returns standard HTTP status codes with a JSON body. Legacy API returns an error code in the response envelope regardless of HTTP status.
REST error response
HTTP 400
{ "message": "account.domain is required" }
Legacy error response (JSON)
{ "errorCode": "201",
"errorMessage": "Missing parameter(s)",
"statusCode": "ERROR" }
Links
Create, read, update, and delete short links. All endpoints require authentication.
/api/links
🔒 auth required
List links for the current account. Supports pagination and search.
| Parameter | Type | Description | |
|---|---|---|---|
| q | optional | string | Full-text search across token, URL, description |
| page | optional | integer | Page number (default 1, 20 per page) |
| sort | optional | string | lastCreated | byHits | todaysLinks | tokenMatch |
/api/links/recent
🔒 auth required
Returns the 10 most recently created links.
/api/links/popular
🔒 auth required
Returns the 10 most-clicked links in the last 30 days.
/api/links/search
🔒 auth required
Search links by token, URL, or description.
| Parameter | Type | Description | |
|---|---|---|---|
| q | required | string | Search term |
/api/links
🔒 auth required
Create a new short link. If allow_duplicate_urls is false (default), returns the existing link when the same URL already exists.
| Parameter | Type | Description | |
|---|---|---|---|
| url | required | string | Destination URL |
| token | optional | string | Custom slug. Random Base58 generated if omitted. |
| description | optional | string | |
| redirectCode | optional | integer | 301 or 302 (default 301) |
| passThrough | optional | boolean | Append incoming query params to destination |
| expiresAt | optional | datetime | ISO 8601. Link becomes inactive after this time. |
| expiredUrl | optional | string | Redirect destination after expiry |
| password | optional | string | Bcrypt-hash stored; visitor must enter this password |
| campaignId | optional | integer | Associate a campaign (pixels + analytics tags) |
| overridePixelIds | optional | integer[] | Per-link pixel overrides (replaces campaign pixels) |
| geoDestinations | optional | object | Map of ISO 3166-1 alpha-2 country code → destination URL |
| deviceDestinations | optional | object | Keys: mobile, tablet, desktop, smarttv → destination URL |
| abVariants | optional | object[] | A/B test variants: [{ url, weight, label? }] |
{ "url": "https://example.com/page", "token": "promo24", "redirectCode": 302 }
← { "id": 42, "token": "promo24", "shortUrl": "https://go.yourdomain.com/promo24", "url": "..." }
/api/links/:id
🔒 auth required
Get a single link by numeric ID.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer | Link ID |
/api/links/:id
🔒 auth required
Update a link. All fields are optional; only supplied fields are changed.
| Parameter | Type | Description | |
|---|---|---|---|
| url | optional | string | New destination URL |
| token | optional | string | New custom slug (must be unique within account) |
| description | optional | string | |
| redirectCode | optional | integer | 301 or 302 |
| passThrough | optional | boolean | |
| expiresAt | optional | datetime | ISO 8601 or null to clear |
| expiredUrl | optional | string | |
| password | optional | string | Set new password, or null to remove |
| campaignId | optional | integer | null to remove campaign association |
| overridePixelIds | optional | integer[] | |
| geoDestinations | optional | object | null to clear all geo rules |
| deviceDestinations | optional | object | null to clear all device rules |
| abVariants | optional | object[] | null to clear A/B test |
/api/links/:id
🔒 auth required
Delete a link permanently.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer | Link ID |
/api/links/:id/chart_data
🔒 auth required
Daily click counts for a link. Returns an array of { date, clicks } objects from link creation to today.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer | Link ID |
← [{ "date": "2025-06-01", "clicks": 42 }, ...]
/api/links/:id/qr_image
🔒 auth required
QR code image for the link's short URL.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer | Link ID |
| format | optional | string | png (default) or svg |
| size | optional | integer | Pixel width (default 200) |
/api/links.csv
🔒 auth required
Export all links as a CSV file. Columns: Long URL, Domain, Token, Created By, Created At, Total Visits, Description, HTTP Status Code, Allow Parameter Pass Through.
/api/links/import
🔒 auth required
Bulk import links from a CSV or TSV file. Column 0 = URL, Column 1 = token (optional). Multipart form upload; field name: file.
/api/links/:id/routing
🔒 auth required
Get geo, device, and A/B routing rules for a link.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer | Link ID |
Pixels & Analytics Tags
Retargeting pixels and analytics tags fire from an interstitial page on redirect — before the visitor reaches the destination. Supported platforms: Facebook, Google Ads, LinkedIn, TikTok, Pinterest, Twitter/X, Snapchat (pixels); GA4, Segment, Matomo, Plausible, Fathom, Mixpanel (analytics tags).
/api/pixels
🔒 auth required
List all retargeting pixels configured for the account.
/api/pixels
🔒 auth required
Add a retargeting pixel. Paste the full platform snippet — the server extracts the pixel ID; the raw snippet is discarded.
| Parameter | Type | Description | |
|---|---|---|---|
| platform | required | string | facebook | google_ads | linkedin | tiktok | pinterest | twitter | snapchat | custom |
| name | required | string | Display label |
| snippet | required | string | Full platform snippet (ID is extracted server-side) |
{ "platform": "facebook", "name": "Main FB pixel", "snippet": "fbq('init', '123456789')" }
← { "id": 3, "platform": "facebook", "name": "Main FB pixel", "pixelId": "123456789" }
/api/pixels/:id
🔒 auth required
Remove a pixel. Existing link associations are cleared.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer |
/api/analytics-tags
🔒 auth required
List all analytics tags configured for the account.
/api/analytics-tags
🔒 auth required
Add an analytics tag. Paste the full platform snippet.
| Parameter | Type | Description | |
|---|---|---|---|
| platform | required | string | ga4 | segment | matomo | plausible | fathom | mixpanel | custom |
| name | required | string | Display label |
| snippet | required | string | Full platform snippet |
/api/analytics-tags/:id
🔒 auth required
Remove an analytics tag.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer |
Campaigns
Campaigns bundle pixels and analytics tags that fire together on redirect. Associate a campaign with a link to fire all its tags on every click from that link.
/api/campaigns
🔒 auth required
List all campaigns.
/api/campaigns/:id
🔒 auth required
Get a single campaign with its associated pixels and analytics tags.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer |
/api/campaigns
🔒 auth required
Create a campaign.
| Parameter | Type | Description | |
|---|---|---|---|
| name | required | string | Display label |
| pixelIds | optional | integer[] | Pixel IDs to include |
| analyticsTagIds | optional | integer[] | Analytics tag IDs to include |
{ "name": "Summer 2025", "pixelIds": [1,3], "analyticsTagIds": [2] }
/api/campaigns/:id
🔒 auth required
Update a campaign name or its pixel/tag associations.
| Parameter | Type | Description | |
|---|---|---|---|
| name | optional | string | |
| pixelIds | optional | integer[] | Replaces existing pixel list |
| analyticsTagIds | optional | integer[] | Replaces existing analytics tag list |
/api/campaigns/:id
🔒 auth required
Delete a campaign. Existing link associations are cleared.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer |
Webhooks
Receive real-time click events at any HTTP endpoint. Deliveries are HMAC-SHA256 signed and retried up to 5 times with exponential backoff (1 min → 5 min → 30 min → 2 hr → 8 hr).
/api/account/webhooks
🔒 auth required
List all webhooks for the account.
/api/account/webhooks
🔒 auth required
Create a webhook. A secret is auto-generated and returned once — store it immediately.
| Parameter | Type | Description | |
|---|---|---|---|
| url | required | string | HTTPS endpoint to receive events |
| events | optional | string[] | Event types to subscribe to. Default: ["click"] |
{ "url": "https://yourapp.com/hooks/shortswitch", "events": ["click"] }
← { "id": 1, "url": "...", "secret": "whsec_...", "events": ["click"] }
/api/account/webhooks/:id
🔒 auth required
Update a webhook.
| Parameter | Type | Description | |
|---|---|---|---|
| url | optional | string | |
| events | optional | string[] | |
| enabled | optional | boolean |
/api/account/webhooks/:id/rotate-secret
🔒 auth required
Generate a new HMAC secret. The old secret is invalidated immediately.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer |
/api/account/webhooks/:id
🔒 auth required
Delete a webhook and all its delivery history.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer |
{
"event": "click",
"timestamp": "2025-06-01T14:22:00.000Z",
"account_id": 42,
"link": {
"id": 1234,
"token": "promo24",
"destination": "https://www.example.com/page",
"domain": "go.yourdomain.com"
},
"click": {
"country": "US",
"subdivision": "CA",
"city": "San Francisco",
"device_type": "desktop",
"referrer_domain": "google.com",
"user_agent": "Mozilla/5.0 ..."
}
}
All geo and referrer fields are null if unavailable. Verify the signature: sha256=HMAC-SHA256(secret, rawBody) in the X-ShortSwitch-Signature header.
Account & Domains
Manage account settings and custom short-link domains. Domain management requires account admin role.
/api/account
🔒 auth required
Get current account settings and subscription state.
/api/account
🔒 auth required
Update account settings.
| Parameter | Type | Description | |
|---|---|---|---|
| name | optional | string | Account display name |
| allowDuplicateUrls | optional | boolean | Allow multiple tokens for the same URL |
| brandedRedirectType | optional | string | toolbar | interstitial |
| customInvalidUrl | optional | string | Redirect target for invalid tokens |
| enableToolbar | optional | boolean | Requires subscription feature gate |
| homepageRedirectUrl | optional | string | Redirect for bare domain requests |
| prependPathSupport | optional | boolean | |
| prependPath | optional | string | Path prefix for short URLs |
| useCaseInsensitiveTokens | optional | boolean | |
| restrictUrlSchemes | optional | boolean | Only allow http/https/ftp/mailto |
| filterUrls | optional | boolean | Enable SURBL spam check on link creation |
| toolbarHtml | optional | string | Custom HTML for branded toolbar |
| toolbarStyling | optional | string | Inline CSS for toolbar |
| toolbarStylingUrl | optional | string | External CSS URL for toolbar |
| toolbarTitle | optional | string |
/api/account/stats
🔒 auth required
Total link count and visit count for the account.
/api/account/domains
🔒 auth required
List all custom short-link domains for the account.
/api/account/domains
🔒 auth required
Add a new custom domain. If a CloudFront distribution is already deployed for this account, a full reprovision is triggered automatically (new ACM cert with all domains as SANs).
| Parameter | Type | Description | |
|---|---|---|---|
| domain | required | string | e.g. go.yourdomain.com |
← { "domain": { "id": 5, "domain": "go.yourdomain.com" }, "provisioning": true }
/api/account/domains/:domain
🔒 auth required
Remove a domain. Cannot remove the last domain on an account.
| Parameter | Type | Description | |
|---|---|---|---|
| domain | required | string | Domain value (not ID) |
/api/account/domains/:id/primary
🔒 auth required
Set a domain as the primary domain for permalink generation.
| Parameter | Type | Description | |
|---|---|---|---|
| id | required | integer |
/api/account/cloudfront-status
🔒 auth required
Get the current CloudFront provisioning status for this account.
Legacy API
Drop-in compatible with integrations built against the original API. Authenticates via ?apiKey=<key>. Default response format is XML; pass ?format=json or ?format=simple (plain text) to change.
<?xml version="1.0" encoding="UTF-8"?>
<shortSwitch>
<errorCode>0</errorCode>
<errorMessage/>
<statusCode>OK</statusCode>
<results>
<shortUrl>https://go.yourdomain.com/abc123</shortUrl>
<longUrl>https://www.example.com/long/path</longUrl>
<hash>abc123</hash>
</results>
</shortSwitch>
Shorten / Create
/shorten
Shorten a URL. Also available as GET. Aliases: /create.
| Parameter | Type | Description | |
|---|---|---|---|
| longUrl / url | required | string | Destination URL |
| token / hash | optional | string | Custom slug |
| domain | optional | string | Override account primary domain |
| passThrough | optional | boolean | Pass incoming query params to destination |
| apiKey | required | string | User API key |
| format | optional | string | json | xml | simple |
← { "results": { "shortUrl": "...", "longUrl": "...", "hash": "abc123" } }
/* simple format: returns just the short URL as plain text */
Expand / Info / Stats
/expand
Expand a short URL to its destination.
| Parameter | Type | Description | |
|---|---|---|---|
| hash / token / permalink / shortUrl | required | string | Any form of the short URL or just the token |
| apiKey | required | string |
← { "results": { "longUrl": "https://www.example.com/..." } }
/info
Get metadata about a short link.
| Parameter | Type | Description | |
|---|---|---|---|
| hash / token | required | string | |
| keys | optional | string | Comma-separated field names to include in results |
| apiKey | required | string |
← { "results": { "hash": "abc123", "longUrl": "...", "shortUrl": "...", "shortenedByUser": "Jane" } }
/stats
Get lifetime click count for a short link.
| Parameter | Type | Description | |
|---|---|---|---|
| hash / token | required | string | |
| apiKey | required | string |
← { "results": { "hash": "abc123", "clicks": 1042 } }
/validate
Validate whether a URL and/or token is acceptable without creating a link.
| Parameter | Type | Description | |
|---|---|---|---|
| longUrl / url | required | string | |
| token | optional | string | |
| apiKey | required | string |
/errors
Returns the full error code dictionary as a list of { code, message } objects.
| Parameter | Type | Description | |
|---|---|---|---|
| apiKey | required | string |
List / Delete
/list
List short links. By default lists all links for the account. Pass ?account=no to list only the authenticated user's links.
| Parameter | Type | Description | |
|---|---|---|---|
| account | optional | string | Pass "no" to filter to current user's links only |
| apiKey | required | string |
← { "results": { "links": [...], "count": 42 } }
/delete
Delete a short link.
| Parameter | Type | Description | |
|---|---|---|---|
| hash / token | required | string | |
| apiKey | required | string |
Legacy Error Codes
| Code | Message |
|---|---|
| 0 | OK |
| 201 | Missing parameter(s) |
| 203 | You must be authenticated |
| 205 | Invalid API key |
| 208 | There was a problem creating your shortened link |
| 209 | Your account must be confirmed |
| 1204 | %s is not a valid ShortSwitch hash |
| 1206 | URL already shortened |
| 1212 | Custom keyword already in use |
| 1213 | Could not find long URL for that short URL |
Questions? Contact us or check the @simplewebauthn docs for WebAuthn integration help.