LinkQR API Documentation
Three things are available: sign in with a LinkQR account (OAuth 2.0), short link creation, and QR code generation. Short link & QR endpoints are currently limited to admin accounts.
Login with LinkQR
OAuth 2.0 + PKCE
Short Link API
Admin only
QR Code API
PNG · SVG · JSON
Base URL & format
https://linkqr.id/api/public/v1All responses are JSON. Errors use { "error": "code", "error_description": "detail" }.
GET https://linkqr.id/api/public/v1/oauth/discovery # metadata OAuth (issuer, endpoint, scope)1. Login with LinkQR (OAuth 2.0)
The flow mirrors "Sign in with Google": redirect the user to the LinkQR consent page, the user approves, then you exchange the code for an access token.
Step 0 — register your app. A LinkQR admin creates the app under Admin → API & OAuth to get a client_id, client_secret and to register the Redirect URI.
Step 1 — send the user to the consent page
GET https://linkqr.id/oauth/authorize
?response_type=code
&client_id=lqr_client_xxx
&redirect_uri=https://app-anda.com/callback
&scope=openid%20profile%20email%20links%20qr
&state=RANDOM_STRING
&code_challenge=BASE64URL_SHA256(verifier) # opsional (PKCE)
&code_challenge_method=S256If the user is signed out, LinkQR shows the sign-in page first and returns to consent afterwards. On approval the user is redirected to redirect_uri with ?code=...&state=... On denial: ?error=access_denied.
Step 2 — exchange the code for tokens
curl -X POST https://linkqr.id/api/public/v1/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "authorization_code",
"code": "lqr_code_...",
"redirect_uri": "https://app-anda.com/callback",
"client_id": "lqr_client_xxx",
"client_secret": "lqr_secret_xxx",
"code_verifier": "VERIFIER"
}'
# 200 OK
{
"access_token": "lqr_at_...",
"refresh_token": "lqr_rt_...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid profile email links qr"
}The client secret may also be sent via HTTP Basic auth. Access tokens live 1 hour, refresh tokens 30 days (single-use / rotating).
Step 3 — fetch the user
curl https://linkqr.id/api/public/v1/oauth/userinfo -H "Authorization: Bearer lqr_at_..."
{
"sub": "uuid-user",
"email": "user@example.com",
"email_verified": true,
"name": "Budi Santoso",
"given_name": "Budi",
"family_name": "Santoso",
"phone_number": "+628...",
"city": "Jakarta",
"country": "ID",
"is_admin": false,
"scope": "openid profile email"
}Refresh & revoke
curl -X POST https://linkqr.id/api/public/v1/oauth/token \
-H "Content-Type: application/json" \
-d '{"grant_type":"refresh_token","refresh_token":"lqr_rt_...","client_id":"...","client_secret":"..."}'
curl -X POST https://linkqr.id/api/public/v1/oauth/revoke \
-H "Content-Type: application/json" \
-d '{"token":"lqr_at_..."}'2. Short Link API (admin only)
Requires an access token from a LinkQR admin account with the links scope. Non-admin accounts get 403 forbidden.
# Buat short link (slug opsional)
curl -X POST https://linkqr.id/api/public/v1/links \
-H "Authorization: Bearer lqr_at_..." \
-H "Content-Type: application/json" \
-d '{"url":"https://contoh.com/halaman-panjang","slug":"promo2026"}'
# 201 Created
{
"code": "promo2026",
"short_url": "https://linkqr.id/promo2026",
"target_url": "https://contoh.com/halaman-panjang",
"clicks": 0,
"qr_url": "https://linkqr.id/api/public/v1/qr?data=https%3A%2F%2Flinkqr.id%2Fpromo2026",
"created_at": "2026-08-11T07:00:00.000Z"
}
# Daftar short link
curl "https://linkqr.id/api/public/v1/links?limit=20&offset=0" -H "Authorization: Bearer lqr_at_..."
# Hapus
curl -X DELETE https://linkqr.id/api/public/v1/links/promo2026 -H "Authorization: Bearer lqr_at_..."URLs flagged as gambling/phishing/unsafe are rejected with url_blocked. A taken slug returns 409 slug_taken.
3. QR Code API (admin only)
# PNG (default)
curl "https://linkqr.id/api/public/v1/qr?data=https://linkqr.id/promo2026&size=512" \
-H "Authorization: Bearer lqr_at_..." --output qr.png
# SVG
curl "https://linkqr.id/api/public/v1/qr?data=https://linkqr.id&format=svg&color=%230a0a0a" \
-H "Authorization: Bearer lqr_at_..."
# JSON (data URL, cocok untuk <img src="...">)
curl "https://linkqr.id/api/public/v1/qr?data=https://linkqr.id&format=json" \
-H "Authorization: Bearer lqr_at_..."| Param | Required | Description |
|---|---|---|
data | yes | Text/URL to encode (max 1200 chars) |
size | - | 64–1024 px (default 320) |
format | - | png · svg · json |
color | - | Hex color, e.g. #0a0a0a |
Error codes
401 invalid_client | Wrong client_id/client_secret or inactive app |
400 invalid_grant | Code/refresh token expired, reused, or PKCE failed |
401 invalid_token | Access token invalid or expired |
403 forbidden | Endpoint limited to admin accounts |
403 insufficient_scope | Token missing the links/qr scope |
409 slug_taken | Slug already used |
Notes
- Any LinkQR user can sign in via OAuth; only the short link & QR endpoints are admin-restricted for now.
- Always keep client_secret server-side, never in the browser.
- Use state to prevent CSRF and PKCE for mobile/SPA clients.
- Need an OAuth app? Contact a LinkQR admin. Sign in