Authentication
Two ways to authenticate with the s.id API, API keys for server-to-server, OAuth 2.0 for acting on behalf of users.
Server-to-server access
API keys authenticate server-to-server integrations. Create one in Dashboard → Developer → API Keys, pick your scopes, and pass it as a Bearer token.
| Scope | Access |
|---|---|
links:read | List and read links |
links:write | Create and update links (create, edit, restore) |
links:archive | Archive links |
links:analytics | Read per-link click statistics and lifetime counts |
qr:read | Read QR code settings (global and per-link) |
qr:write | Customize QR code settings (global and per-link) |
user:read | Read the authenticated user profile and account quota |
microsites:read | Read microsites |
microsites:write | Create, update and manage components of microsites |
microsites:delete | Delete microsites and their components |
bash
Authorization: Bearer sk_live_...bash
curl https://api.s.id/v2/links \
-H "Authorization: Bearer sk_live_..."- Keys start with sk_live_ and are shown only once at creation.
- Request only the minimum scopes your integration needs.
- Revoke keys immediately if compromised, create a new one.
- Never expose API keys client-side (browsers, mobile apps).
Authorization flow
Redirect the user to s.id for consent, verify the callback state, then exchange the single-use code for an access token and rotating refresh token.
- Generate an unpredictable state value, store it in the user session, and verify an exact match on callback to prevent CSRF.
- Use a redirect_uri that exactly matches one registered for your OAuth application.
PKCE required, no client secret
For SPAs, mobile apps, and CLIs. Create a random code_verifier, send its S256 challenge on authorize, then send the original verifier during token exchange.
bash
https://api.s.id/oauth/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&
scope=links%3Aread%20links%3Awrite&
state=RANDOM_CSRF_VALUE&
code_challenge=BASE64URL_SHA256_VERIFIER&
code_challenge_method=S256bash
curl -X POST https://api.s.id/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=YOUR_CLIENT_ID" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://app.example.com/callback" \
-d "code_verifier=ORIGINAL_RANDOM_VERIFIER"Client secret on a trusted backend
For server-rendered or backend applications that can keep a client_secret confidential. PKCE remains optional and is recommended as defense in depth.
bash
https://api.s.id/oauth/authorize?
response_type=code&
client_id=YOUR_CLIENT_ID&
redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback&
scope=links%3Aread%20links%3Awrite&
state=RANDOM_CSRF_VALUEbash
curl -X POST https://api.s.id/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://app.example.com/callback"| Access token | Description |
|---|---|
access_token | Expires after 1 hour |
refresh_token | Expires after 30 days |
code | Single-use; expires after 10 minutes |
bash
curl -X POST https://api.s.id/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "client_id=YOUR_CLIENT_ID" \
-d "refresh_token=CURRENT_REFRESH_TOKEN"bash
curl -X POST https://api.s.id/oauth/revoke \
-H "Content-Type: application/json" \
-d '{"token":"TOKEN_TO_REVOKE"}'| Discovery and token operations | Description |
|---|---|
https://api.s.id/.well-known/oauth-authorization-server | Discover endpoint URLs, supported scopes, and PKCE methods through RFC 8414 metadata. |
POST /oauth/introspect | Confidential resource servers can check whether a token is active and inspect its scopes. |
POST /oauth/revoke | Revoke access or refresh tokens when a user disconnects your integration. |
GET /oauth/userinfo | Read the profile associated with an OAuth access token carrying user:read. |