API reference
Full HTTPS API reference: link creation, slug checks, expirations, routing, and conversions.
Prerequisites
- An active Nimriz workspace.
- A Workspace API Key generated from Dashboard → Settings → Integrations → API access. This key is used for all link-management API calls.
- A secure server-side environment. Never expose your API key in browser-side code, mobile apps, or public repositories.
- For conversion tracking: a separate Conversion API signing secret (also in Integrations). This secret is used exclusively for the Conversion API and is not the same as the workspace API key.
Fundamental rules
- All write operations (creating links, updating slugs, changing passwords) must come from a trusted server backend.
- Link uniqueness is domain-bound:
(domain_id, short_code)must be unique, not justshort_codeglobally. - Redirects default to
302. Only request301when you explicitly want a permanent redirect-browsers cache 301s aggressively. - Host matching is strict.
example.comandwww.example.comare completely separate domains in Nimriz.
Canonical hosts
| Purpose | Host |
|---|---|
| Browser dashboard and auth routes | https://app.nimriz.com |
| Machine-facing API traffic | https://api.nimriz.com |
| Redirect traffic | Your short domain (e.g., https://links.example.com) |
Use api.nimriz.com for all programmatic link-management calls. Short-link domains are redirect surfaces-do not use them as the long-term machine API host.
Authentication
Every link-management API call requires a workspace API key in one of these headers:
Authorization: Bearer <WORKSPACE_API_KEY>
X-Nim-Api-Key: <WORKSPACE_API_KEY>
Both formats are supported. The Authorization: Bearer style is preferred for consistency with standard HTTP auth patterns.
The Conversion API uses a different secret. Do not use your workspace API key for Conversion API requests.
Resource identifiers
| Identifier | Type | Description |
|---|---|---|
domain_id | UUID | The target short-link domain. |
url_id | UUID | The created short link. Use this as your durable reference-slugs can change, but url_id is permanent. |
short_code | String | The slug path segment (e.g., spring-launch). |
short_url | String | The full short URL (e.g., https://links.example.com/spring-launch). |
POST /api/shorten-Create a link
Creates a single short link.
POST https://api.nimriz.com/api/shorten
Authorization: Bearer <WORKSPACE_API_KEY>
Content-Type: application/json
Request body:
{
"domain_id": "00000000-0000-0000-0000-000000000000",
"long_url": "https://example.com/landing?utm_source=twitter&utm_medium=social&utm_campaign=spring",
"custom_slug": "spring-launch",
"expires_at": "2026-12-31T23:59:59Z",
"password": "optional-secret",
"redirect_status_code": 302
}
| Field | Required | Description |
|---|---|---|
domain_id | Yes | UUID of the target domain. |
long_url | Yes | The destination URL. Must use https:// (or http:// if the domain policy allows). |
custom_slug | No | Your chosen slug. If omitted, Nimriz generates a random one. |
expires_at | Conditional | ISO 8601 timestamp. Required by some domain policies. |
password | No | Plain-text password for password protection (plan-gated). |
redirect_status_code | No | 302 (default) or 301. Avoid 301 unless the destination is truly permanent. |
Successful response:
{
"url_id": "22222222-2222-2222-2222-222222222222",
"short_code": "spring-launch",
"short_url": "https://links.example.com/spring-launch",
"expires_at": "2026-12-31T23:59:59.000Z",
"password_protected": false
}
POST /api/shorten/bulk-Bulk create links
Creates up to 25 links in a single request. Designed for imports and automation jobs that require idempotent retries.
POST https://api.nimriz.com/api/shorten/bulk
Authorization: Bearer <WORKSPACE_API_KEY>
Content-Type: application/json
Request body:
{
"domain_id": "00000000-0000-0000-0000-000000000000",
"items": [
{
"client_row_id": "row-1",
"idempotency_key": "import-session-abc-row-1",
"long_url": "https://example.com/a",
"custom_slug": "campaign-a"
},
{
"client_row_id": "row-2",
"idempotency_key": "import-session-abc-row-2",
"long_url": "https://example.com/b"
}
]
}
| Field | Required | Description |
|---|---|---|
domain_id | Yes | Applies to all items in the batch. |
items[].client_row_id | Yes | Your stable identifier for this row within the batch. Returned in the response so you can match results to inputs. |
items[].idempotency_key | Yes | A stable key for this exact mutation. If you replay the same key, Nimriz returns the stored result instead of creating a duplicate. |
items[].long_url | Yes | Destination URL for this row. |
items[].custom_slug | No | Custom slug for this row. |
items[].expires_at | No | Per-row expiration. |
Rules:
- Maximum 25 items per request.
- Validation failures are returned per-row-a single row failing does not fail the entire batch.
- Replaying the same
idempotency_keyreturns the stored result withidempotent: true.
Successful response:
{
"results": [
{
"client_row_id": "row-1",
"ok": true,
"idempotent": false,
"url_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"short_code": "campaign-a",
"short_url": "https://links.example.com/campaign-a"
},
{
"client_row_id": "row-2",
"ok": false,
"error": "Slug is reserved",
"code": "slug_reserved"
}
]
}
POST /api/check-slug-Check slug availability
Validates whether a candidate slug is available on a specific domain before attempting creation.
{
"domain_id": "00000000-0000-0000-0000-000000000000",
"slug": "spring-launch"
}
Available:
{ "available": true }
Not available:
{
"available": false,
"error": "Slug is reserved",
"code": "slug_reserved"
}
PUT /api/update-slug-Update a slug
Changes the slug on an existing link. The old slug stops working immediately after the update.
{
"url_id": "22222222-2222-2222-2222-222222222222",
"new_slug": "spring-launch-v2"
}
Response:
{
"short_code": "spring-launch-v2",
"short_url": "https://links.example.com/spring-launch-v2"
}
PUT /api/update-expiration-Update or remove expiration
Sets, changes, or removes the expiration time on a link.
{
"url_id": "22222222-2222-2222-2222-222222222222",
"expires_at": "2026-12-31T23:59:59Z"
}
To remove expiration (when policy allows):
{
"url_id": "22222222-2222-2222-2222-222222222222",
"expires_at": null
}
Response:
{
"url_id": "22222222-2222-2222-2222-222222222222",
"expires_at": "2026-12-31T23:59:59.000Z",
"was_expired": false
}
PUT /api/update-password-Set or remove password protection
Set or update a password:
{
"url_id": "22222222-2222-2222-2222-222222222222",
"password": "new-password"
}
Remove password protection:
{
"url_id": "22222222-2222-2222-2222-222222222222",
"password": null
}
POST /api/links/routing-rules-Save routing rules
Saves the complete ordered routing ruleset for a link. This replaces all existing rules-it is not an additive operation.
{
"url_id": "22222222-2222-2222-2222-222222222222",
"operation": "save",
"rules": [
{
"name": "US mobile users",
"enabled": true,
"actionType": "destination_override",
"conditions": {
"countryIn": ["US"],
"deviceTypeIn": ["mobile"],
"deviceOsIn": [],
"timeWindows": []
},
"destinationUrl": "https://example.com/us-mobile"
}
]
}
The rules array is ordered-the first matching enabled rule wins at redirect time. Supported actionType values: destination_override, ab_split, deep_link.
POST /api/conversions/callback/:workspace_id-Record a conversion
Sends a signed conversion event from your backend.
POST https://api.nimriz.com/api/conversions/callback/<WORKSPACE_ID>
Content-Type: application/json
X-Nim-Timestamp: <unix-seconds>
X-Nim-Signature: v1=<hex-hmac-sha256>
Idempotency-Key: <stable-key>
The signature is computed as HMAC-SHA256("${X-Nim-Timestamp}.${raw_request_body}", CONVERSION_SECRET).
Example request body:
{
"event_name": "sale",
"event_time": "2026-03-26T12:00:00.000Z",
"event_id": "evt_sale_123",
"user_data": {
"click_id": "nimct_exampletoken",
"external_id": "cust_123"
},
"custom_data": {
"order_id": "order_abc",
"value": 99.00,
"currency": "USD"
}
}
Supported event_name values: lead, sale, refund, cancellation, reversal.
Link Search and Retrieval API
GET /api/v1/links/find-Find link by URL or Domain/Slug
Look up a specific link based on its short URL or its domain ID and short code.
GET https://api.nimriz.com/api/v1/links/find?short_url=https://links.example.com/spring-launch
Authorization: Bearer <WORKSPACE_API_KEY>
Supported query parameters (must provide either short_url OR domain_id + short_code):
| Parameter | Description |
|---|---|
short_url | Full short URL to look up. |
domain_id | Domain UUID. |
short_code | Short code on the domain. |
GET /api/v1/links-List recent links
Returns a list of recently created links for the specified workspace.
GET https://api.nimriz.com/api/v1/links?account_id=WORKSPACE_UUID&limit=50
Authorization: Bearer <WORKSPACE_API_KEY>
Supported query parameters:
| Parameter | Description |
|---|---|
account_id | Workspace UUID. |
limit | Max number of links to return (max 100, default 50). |
GET /api/v1/links/:id-Get link by ID
Returns a single link record.
GET https://api.nimriz.com/api/v1/links/22222222-2222-2222-2222-222222222222
Authorization: Bearer <WORKSPACE_API_KEY>
QR API
Professional and Enterprise workspaces can automate QR rendering, preset management, and QR-only link analytics through the same customer API host.
QR API rules
- QR endpoints require the same workspace API key auth model shown above.
- QR rendering always targets an existing Nimriz
url_id; QR remains a view of a short link, not a separate QR object. - The API uses the same validation and plan checks as the dashboard, including QR CTA layout access and custom CTA text restrictions.
- The same canonical QR style state drives dashboard previews, downloads, preset saves, and API renders.
Available QR endpoints
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/qr/generate | Render a QR asset for an existing link. |
GET | /api/v1/qr/presets | List QR presets visible to the workspace. |
POST | /api/v1/qr/presets | Create a QR preset. |
PUT | /api/v1/qr/presets/:id | Update a QR preset. |
DELETE | /api/v1/qr/presets/:id | Delete a QR preset. |
GET | /api/v1/links/:id/qr | Download the link's effective QR asset. |
GET | /api/v1/links/:id/analytics | Return link analytics with touch_type=qr_scan by default. |
POST /api/v1/qr/generate-Render a QR asset
Renders a QR image from the requested link's saved QR state, with optional preset or style overrides.
POST https://api.nimriz.com/api/v1/qr/generate
Authorization: Bearer <WORKSPACE_API_KEY>
Content-Type: application/json
{
"url_id": "22222222-2222-2222-2222-222222222222",
"format": "png",
"size": 1024,
"force_regenerate": false,
"qr_preset_id": "55555555-5555-5555-5555-555555555555",
"style": {
"background": { "mode": "transparent" }
}
}
Notes:
url_idis required and must belong to a link the API key can access.formatcan bepngorsvg. Defaults tosvgwhen omitted.sizeis clamped to128-2048. The default is512.force_regenerate: truebypasses any cached asset and rebuilds the QR output.qr_preset_idis optional.styleis optional and must match the same QR style schema the dashboard uses.
Successful responses return the QR asset itself with the correct image content type and download headers.
GET /api/v1/qr/presets-List QR presets
Lists QR presets for the authenticated workspace.
GET https://api.nimriz.com/api/v1/qr/presets
Authorization: Bearer <WORKSPACE_API_KEY>
Successful responses return:
{
"ok": true,
"presets": [
{
"id": "55555555-5555-5555-5555-555555555555",
"name": "Conference handout",
"style": {},
"is_default": true,
"created_at": "2026-04-12T10:00:00.000Z",
"updated_at": "2026-04-12T10:00:00.000Z",
"logo_preview_url": "https://..."
}
]
}
POST /api/v1/qr/presets-Create a QR preset
Creates a reusable QR preset using the same style contract as the dashboard.
{
"name": "Conference handout",
"is_default": true,
"style": {
"background": { "mode": "transparent" }
}
}
Rules:
- Preset names are limited to 120 characters.
- Plan preset limits still apply.
- Frame entitlement checks still apply.
- If
is_defaultistrue, Nimriz clears the previous default preset in that workspace.
PUT /api/v1/qr/presets/:id-Update a QR preset
Updates one or more preset fields.
{
"name": "Conference handout v2",
"is_default": false,
"style": {
"background": { "mode": "single", "color": "#ffffff" }
}
}
You can send any subset of name, is_default, and style. The same style validation and frame plan checks apply as on create.
DELETE /api/v1/qr/presets/:id-Delete a QR preset
Deletes the target preset and returns the deleted preset id on success.
GET /api/v1/links/:id/qr-Download the effective QR asset
Fetches the saved QR asset for an existing link.
GET https://api.nimriz.com/api/v1/links/22222222-2222-2222-2222-222222222222/qr?format=svg&size=1024&force_regenerate=1
Authorization: Bearer <WORKSPACE_API_KEY>
Supported query parameters:
| Parameter | Description |
|---|---|
format | png or svg. Defaults to svg. |
size | Optional size from 128-2048. Defaults to 512. |
force_regenerate | 1, true, yes, or on forces a fresh render. |
GET /api/v1/links/:id/analytics-Fetch QR-filtered analytics
Returns per-day totals and points for the target link. If you do not pass touch_type, the endpoint defaults to qr_scan.
GET https://api.nimriz.com/api/v1/links/22222222-2222-2222-2222-222222222222/analytics?range_days=30&include_bots=0&touch_type=qr_scan
Authorization: Bearer <WORKSPACE_API_KEY>
Supported query parameters:
| Parameter | Description |
|---|---|
range_days | Optional daily range from 1-365. Defaults to 30. |
include_bots | 0/1 or boolean-like values. Defaults to 0. |
touch_type | qr_scan or short_link_click. Defaults to qr_scan. |
Successful responses return:
{
"ok": true,
"url_id": "22222222-2222-2222-2222-222222222222",
"range_days": 30,
"include_bots": false,
"touch_type": "qr_scan",
"available": true,
"totals": {
"clicks": 120,
"bot_clicks": 8,
"human_clicks": 112,
"selected_clicks": 112
},
"points": [
{
"date": "2026-04-01",
"clicks": 12,
"bot_clicks": 1,
"human_clicks": 11,
"selected_clicks": 11
}
]
}
Common error codes
| Code | HTTP | Meaning |
|---|---|---|
plan_limit | 403 | The request exceeds the current plan's preset or capability limit. |
monthly_quota_exceeded | 429 | Monthly link-creation quota exceeded. |
slug_reserved | 422 | Slug is a system path or below the minimum length. |
slug_unavailable | 422 | Slug is taken or recently deleted. |
domain_disabled | 422 | Target domain is inactive. |
custom_domain_not_ready | 422 | Domain is not yet Ready for traffic. |
account_suspended | 403 | Account is suspended. |
destination_blocked | 422 | Destination URL uses a forbidden scheme or points to a Nimriz domain. |
invalid_expires_at | 422 | Expiration timestamp is malformed or in the past. |
expiration_required | 422 | Domain policy requires an expiration date. |
expiration_update_not_allowed | 422 | Domain policy blocks expiration changes on this link. |
feature_not_enabled | 403 | The requested feature (e.g., password protection) is not available on your plan. |
routing_rules_not_allowed | 403 | Routing rules are not enabled for this workspace. |
Retry guidance
- Do not retry
4xxerrors immediately-they indicate input problems or policy failures that will not resolve with a retry. - Do retry
429,502,503,504with exponential backoff. - For bulk import jobs, use
POST /api/shorten/bulkwith stableidempotency_keyvalues so retries are safe.