Skip to main content
s.id Logo
View Markdown

API v2 Shortener

Create and manage short links from your app. Base URL: https://api.s.id/v2. Current version 2.0.0, and the full specification is available in OpenAPI format.

Interactive reference

Authentication

Send an API key sk_live_... or an OAuth 2.0 access token in the Authorization: Bearer header. Create API keys in Dashboard > Developer; each key can only use the scopes you choose.

ScopeAccess
links:readList and read links
links:writeCreate and update links (create, edit, restore)
links:archiveArchive links
links:analyticsRead per-link click statistics and lifetime counts
http
Authorization: Bearer sk_live_...

Full authentication guide

Send POST /links with the destination URL. A slug is generated automatically if custom_slug is left empty.

bash
curl -X POST https://api.s.id/v2/links \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"long_url": "https://example.com/long-url", "custom_slug": "[your-alias]"}'
FieldTypeRequiredDescription
long_urlstringYesDestination URL
titlestringNoLink title
custom_slugstringNoCustom slug; generated automatically when empty
passwordstringNoPassword that protects the link
expired_atintegerNoExpiry time as a Unix timestamp (seconds)
domain_aliasstringNoCustom domain used instead of s.id

Example response:

json
{
  "data": {
    "id": 123,
    "short": "[your-alias]",
    "short_url": "https://s.id/[your-alias]",
    "long_url": "https://example.com/long-url",
    "microsite": false,
    "protected": false,
    "disposable": false,
    "adult": false
  },
  "message": "link_created"
}

Endpoints

Kept only on this page until you reload. Clear it when you're done.

User

GET/user

Base URL: https://api.s.id/v2 · Scope: user:read

Responses

CodeDescription
200User profile
401Missing or invalid API key
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: user:read

Save your API key above to send a request.

GET/quota

Returns the authenticated user's current plan limits and usage counters.

Base URL: https://api.s.id/v2 · Scope: user:read

Responses

CodeDescription
200Account quota
401Missing or invalid API key
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: user:read

Save your API key above to send a request.

QR

GET/qr

Returns the account-level (global) QR code settings applied to QR codes by default.

Base URL: https://api.s.id/v2 · Scope: qr:read

Responses

CodeDescription
200Global QR settings
401Missing or invalid API key
403API key lacks the required scope
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: qr:read

Save your API key above to send a request.

PUT/qr

Updates the account-level (global) QR code settings. All fields are optional; omitted fields are left unchanged.

Base URL: https://api.s.id/v2 · Scope: qr:write

Request body

FieldTypeRequiredDescription
logostringNoURL of the logo image embedded in the QR code
colorstringNoForeground color as a hex value, e.g. #1a56db

Responses

CodeDescription
200Updated global QR settings
401Missing or invalid API key
403API key lacks the required scope
422Request validation failed
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: qr:write

Save your API key above to send a request.

GET/links/{short}/qr

Returns the QR code settings for a single link.

Base URL: https://api.s.id/v2 · Scope: qr:read

Parameters

FieldInTypeRequiredDescription
shortpathstringYesThe short code of the link

Responses

CodeDescription
200Link QR settings
401Missing or invalid API key
403API key lacks the required scope
404Resource not found
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: qr:read

Save your API key above to send a request.

PUT/links/{short}/qr

Updates the QR code settings for a single link. All fields are optional; omitted fields are left unchanged.

Base URL: https://api.s.id/v2 · Scope: qr:write

Parameters

FieldInTypeRequiredDescription
shortpathstringYesThe short code of the link

Request body

FieldTypeRequiredDescription
logostringNoURL of the logo image embedded in the QR code
colorstringNoForeground color as a hex value, e.g. #1a56db

Responses

CodeDescription
200Updated link QR settings
401Missing or invalid API key
403API key lacks the required scope
404Resource not found
422Request validation failed
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: qr:write

Save your API key above to send a request.

Microsites

GET/microsites

Returns a paginated list of microsites owned by the authenticated user.

Base URL: https://api.s.id/v2 · Scope: microsites:read

Parameters

FieldInTypeRequiredDescription
limitqueryintegerNo
afterquerystringNoCursor for the next page (opaque string from previous response)

Responses

CodeDescription
200List of microsites
401Missing or invalid API key
403API key lacks the required scope
Try it outScope: microsites:read

Save your API key above to send a request.

POST/microsites

Base URL: https://api.s.id/v2 · Scope: microsites:write

Request body

FieldTypeRequiredDescription
slugstringYesURL-safe identifier (alphanumeric + hyphens/underscores)
titlestringYes
kindstringYesMicrosite category (e.g. personal_branding, brand, other)
themestringNoTheme slug (optional, defaults to the platform default)

Responses

CodeDescription
200Microsite created
400Validation error (slug already taken, quota exceeded, etc.)
401Missing or invalid API key
403API key lacks the required scope
Try it outScope: microsites:write

Save your API key above to send a request.

GET/microsites/{slug}

Base URL: https://api.s.id/v2 · Scope: microsites:read

Parameters

FieldInTypeRequiredDescription
slugpathstringYes

Responses

CodeDescription
200Microsite detail
401Missing or invalid API key
403API key lacks the required scope
404Microsite not found
Try it outScope: microsites:read

Save your API key above to send a request.

PUT/microsites/{slug}

Patches title, description, and/or visibility. All fields are optional.

Base URL: https://api.s.id/v2 · Scope: microsites:write

Parameters

FieldInTypeRequiredDescription
slugpathstringYes

Request body

FieldTypeRequiredDescription
titlestringNo
descriptionstringNo
hidebooleanNoSet true to hide the microsite from public (requires plan that supports visibility toggle)

Responses

CodeDescription
200Updated microsite
401Missing or invalid API key
403API key lacks the required scope
404Microsite not found
Try it outScope: microsites:write

Save your API key above to send a request.

DELETE/microsites/{slug}

Base URL: https://api.s.id/v2 · Scope: microsites:delete

Parameters

FieldInTypeRequiredDescription
slugpathstringYes

Responses

CodeDescription
200Microsite deleted
401Missing or invalid API key
403API key lacks the required scope
404Microsite not found
Try it outScope: microsites:delete

Save your API key above to send a request.

POST/microsites/available

Checks whether a microsite slug is available before creating a microsite.

Base URL: https://api.s.id/v2 · Scope: microsites:read

Request body

FieldTypeRequiredDescription
slugstringYes

Responses

CodeDescription
200Slug availability result
401Missing or invalid API key
403API key lacks the required scope
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: microsites:read

Save your API key above to send a request.

GET/microsites/{slug}/components

Returns the components belonging to a microsite, in display order.

Base URL: https://api.s.id/v2 · Scope: microsites:read

Parameters

FieldInTypeRequiredDescription
slugpathstringYesThe slug of the microsite

Responses

CodeDescription
200List of microsite components
401Missing or invalid API key
403API key lacks the required scope
404Resource not found
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: microsites:read

Save your API key above to send a request.

POST/microsites/{slug}/components

Adds a new component to a microsite. The body is { kind, data, tag? }. The shape of the data object depends on kind. Unknown fields are ignored, validation is per-kind, and invalid input returns 422. All color fields are hex strings (e.g. #1a56db). **Kinds:** PROFILE, LINK, HORIZONTAL_LINK, TEXT, IMAGE, MEDIA, DIVIDER, COUNTDOWN, MAPS, IMAGE_SLIDE, CV, AUTOPLAY_MUSIC, CONTACT, CALENDAR, SHOP_LISTING, SHOP_ITEM, SHOP_LEADERBOARD. **Rules:** - PROFILE, CV and AUTOPLAY_MUSIC are unique — at most one per microsite. - IMAGE_SLIDE requires a plan with the Image Slide feature. - On create the password is always stored empty — set or change it via update (PUT). - Image fields (image, imageBackground, slide image) must be a local asset path, not a remote URL — they must match [/.a-zA-Z0-9_-]+.(jpg|jpeg|png|svg|webp|gif|bmp); any value containing a scheme (https://), //, or .. is rejected. **Shared field groups** (a kind that lists a group accepts all of its fields inside data): - **Button styling** (LINK, CONTACT, CALENDAR): icon (string, max 255), textFont (string, max 100), textPosition (string, max 100), buttonEffect (string, max 100), buttonColor (hex, max 20), buttonBorderColor (hex, max 20), buttonIconBackground (hex, max 20), buttonShadowColor (hex, max 20). - **Spoiler reveal** (TEXT, IMAGE, MEDIA, MAPS, IMAGE_SLIDE, SHOP_LEADERBOARD): isSpoiler (bool), spoilerButtonText (string, max 140), spoilerButtonTextPosition (string, max 100), spoilerButtonIcon (string), spoilerButtonColor (hex, max 20), spoilerButtonFont (string, max 100), spoilerBackground (string, max 100), spoilerBackgroundOpacity (string, max 100), spoilerButtonBorderColor (hex, max 20), spoilerButtonIconBackground (hex, max 20), spoilerButtonShadowColor (hex, max 20). - **Password protection** (LINK, TEXT, IMAGE, MEDIA, MAPS, IMAGE_SLIDE, CONTACT, CV, SHOP_LEADERBOARD): passwordActive (bool), password (string, max 255 — set via update only), passwordMessage (string, max 255).

Base URL: https://api.s.id/v2 · Scope: microsites:write

Parameters

FieldInTypeRequiredDescription
slugpathstringYesThe slug of the microsite

Request body

FieldTypeRequiredDescription
kindPROFILE | LINK | HORIZONTAL_LINK | TEXT | IMAGE | MEDIA | DIVIDER | COUNTDOWN | MAPS | IMAGE_SLIDE | CV | AUTOPLAY_MUSIC | CONTACT | CALENDAR | SHOP_LISTING | SHOP_ITEM | SHOP_LEADERBOARDYesComponent kind. The shape of data depends on this value.
dataobjectYesKind-specific component data. Its shape depends on kind. See the operation description and examples below.
tagstringNoOptional grouping tag

Responses

CodeDescription
200Component created
401Missing or invalid API key
403API key lacks the required scope
404Resource not found
422Request validation failed
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: microsites:write

Save your API key above to send a request.

PUT/microsites/{slug}/components/{componentId}

Updates a single microsite component.

Base URL: https://api.s.id/v2 · Scope: microsites:write

Parameters

FieldInTypeRequiredDescription
slugpathstringYesThe slug of the microsite
componentIdpathstringYesThe component ID

Request body

FieldTypeRequiredDescription
activebooleanYesWhether the component is shown
kindstringYesComponent kind (e.g. LINK, PROFILE, TEXT)
dataobjectYesKind-specific component data

Responses

CodeDescription
200Component updated
401Missing or invalid API key
403API key lacks the required scope
404Resource not found
422Request validation failed
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: microsites:write

Save your API key above to send a request.

DELETE/microsites/{slug}/components/{componentId}

Deletes a single microsite component.

Base URL: https://api.s.id/v2 · Scope: microsites:delete

Parameters

FieldInTypeRequiredDescription
slugpathstringYesThe slug of the microsite
componentIdpathstringYesThe component ID

Responses

CodeDescription
200Component deleted
401Missing or invalid API key
403API key lacks the required scope
404Resource not found
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: microsites:delete

Save your API key above to send a request.

POST/microsites/{slug}/components/order

Reorders a microsite's components according to the provided list of component IDs.

Base URL: https://api.s.id/v2 · Scope: microsites:write

Parameters

FieldInTypeRequiredDescription
slugpathstringYesThe slug of the microsite

Request body

FieldTypeRequiredDescription
ordersstring[]YesComponent IDs in the desired display order

Responses

CodeDescription
200Components reordered
401Missing or invalid API key
403API key lacks the required scope
404Resource not found
422Request validation failed
429Too many requests. Per-tier limits apply, resolved from your s.id plan: a per-credential per-minute rate limit (rate_limit_exceeded) and a daily call quota (api_quota_exceeded), both shared across every integration using your credential (sk_live_* key or OAuth token). OAuth apps also have a secondary per-client_id ceiling (client_rate_limit_exceeded) across all their users' tokens. See GET /v2/quota for your current standing, and the X-RateLimit-* / X-Quota-* response headers.
Try it outScope: microsites:write

Save your API key above to send a request.

OAuth 2.0

GET/oauth/authorize

A plain browser navigation here (no Accept: application/json) 302-redirects to the dash.s.id consent UI, preserving the query string. With Accept: application/json, returns application name, logo, and requested scopes for the consent UI to render.

Base URL: https://api.s.id

Parameters

FieldInTypeRequiredDescription
client_idquerystringYes
redirect_uriquerystringYes
response_typequerycodeYes
scopequerystringNo
statequerystringNoRecommended. Opaque value for CSRF protection. Returned unchanged in the redirect.

Responses

CodeDescription
200Consent screen data
400Bad request
POST/oauth/token

Base URL: https://api.s.id

Request body

FieldTypeRequiredDescription
grant_typeauthorization_code | refresh_tokenNo
codestringNo
redirect_uristringNo
client_idstringNo
client_secretstringNo
refresh_tokenstringNo

Responses

CodeDescription
200Token response
400Invalid grant, unsupported_grant_type, or invalid_client
401Invalid client credentials
POST/oauth/revoke

Revokes an access or refresh token. Always returns 200 OK regardless of whether the token was valid (RFC 7009).

Base URL: https://api.s.id

Request body

FieldTypeRequiredDescription
tokenstringYes

Responses

CodeDescription
200Token revoked
POST/oauth/introspect

Reports whether a token is currently active and, if so, which scopes and client it belongs to (RFC 7662). Client-credential protected: client_id/client_secret identify the caller, not the token owner. Always returns 200 — including for an unknown, expired, or revoked token ({"active": false}) — to avoid leaking token validity to unauthenticated probing.

Base URL: https://api.s.id

Request body

FieldTypeRequiredDescription
tokenstringYes
client_idstringYes
client_secretstringYes

Responses

CodeDescription
200Introspection result
400Missing token/client_id, or invalid client credentials
GET/oauth/userinfo

Returns the profile of the user who authorized the OAuth app. Requires Authorization: Bearer <access_token> (the OAuth access token, not an sk_live_ key).

Base URL: https://api.s.id · Scope: user:read

Responses

CodeDescription
200User profile
401Unauthorized
GET/.well-known/oauth-authorization-server

RFC 8414 discovery document advertising every OAuth endpoint URL, supported scopes, and PKCE methods, so standards-compliant client libraries can configure themselves instead of hard-coding s.id's URLs.

Base URL: https://api.s.id

Responses

CodeDescription
200Authorization server metadata
GET/api/user/oauth/apps

Returns all OAuth clients that have active tokens for the authenticated user. Auth: user session cookie (not API key).

Base URL: https://api.s.id

Responses

CodeDescription
200List of connected apps
401Unauthorized
DELETE/api/user/oauth/apps/{clientId}

Revokes all active tokens granted by the current user to the specified OAuth client.

Base URL: https://api.s.id

Parameters

FieldInTypeRequiredDescription
clientIdpathstringYes

Responses

CodeDescription
200App access revoked
401Unauthorized
404App not found

Analytics

GET/stats

Returns a timeline of clicks plus breakdowns by top links, referers, locations, devices, and browsers for the authenticated account. Date range is gated by subscription plan.

Base URL: https://api.s.id/v2 · Scope: links:analytics

Parameters

FieldInTypeRequiredDescription
startquerystringNoStart date (YYYY-MM-DD). Defaults to 30 days ago.
endquerystringNoEnd date (YYYY-MM-DD). Defaults to today.
additionalquerybooleanNoInclude referer, location, device, browser breakdowns

Responses

CodeDescription
200Account analytics
401Missing or invalid API key
403API key lacks the required scope
Try it outScope: links:analytics

Save your API key above to send a request.

Limits and errors

Each credential is limited per minute. Check your quota with GET /quota.

CredentialLimit
API key or OAuth access token38 requests per minute
OAuth app (all tokens combined)500 requests per minute
CodeMeaning
400Malformed or unsupported request
401Missing, invalid, revoked, or expired credential
403Credential does not have the required scope
404Requested resource was not found
422Request validation failed
429Rate limit exceeded