API reference

Use the HTTPS API reference for link creation, slug checks, expirations, routing, conversions, QR workflows, analytics, and integrations.

Prerequisites

  • An active Nimriz workspace.
  • A Workspace API Key generated from IntegrationsDeveloperBackend API access in the dashboard. 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 just short_code globally.
  • Redirects default to 302. Only request 301 when you explicitly want a permanent redirect-browsers cache 301s aggressively.
  • Host matching is strict. example.com and www.example.com are completely separate domains in Nimriz.

Canonical hosts

PurposeHost
Browser dashboard and auth routeshttps://app.nimriz.com
Machine-facing API traffichttps://api.nimriz.com
Redirect trafficYour 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 same workspace API key authenticates the MCP server, which exposes link, analytics, and delivery-health tools to MCP-compatible AI clients.

The Conversion API uses a different secret. Do not use your workspace API key for Conversion API requests.


Resource identifiers

IdentifierTypeDescription
domain_idUUIDThe target short-link domain.
url_idUUIDThe created short link. Use this as your durable reference-slugs can change, but url_id is permanent.
short_codeStringThe slug path segment (e.g., spring-launch).
short_urlStringThe 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
}
FieldRequiredDescription
domain_idYesUUID of the target domain.
long_urlYesThe destination URL. Must use https:// (or http:// if the domain policy allows).
custom_slugNoYour chosen slug. If omitted, Nimriz generates a random one.
expires_atConditionalISO 8601 timestamp. Required by some domain policies.
passwordNoPlain-text password for password protection (plan-gated).
redirect_status_codeNo302 (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"
    }
  ]
}
FieldRequiredDescription
domain_idYesApplies to all items in the batch.
items[].client_row_idYesYour stable identifier for this row within the batch. Returned in the response so you can match results to inputs.
items[].idempotency_keyYesA stable key for this exact mutation. If you replay the same key, Nimriz returns the stored result instead of creating a duplicate.
items[].long_urlYesDestination URL for this row.
items[].custom_slugNoCustom slug for this row.
items[].expires_atNoPer-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_key returns the stored result with idempotent: 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, "min_length": 5 }

Not available:

{
  "available": false,
  "error": "Slug is reserved",
  "code": "slug_reserved",
  "min_length": 5
}

A slug that is already taken returns "Slug already exists" (HTTP 409, no code field); a recently deleted slug returns "code": "slug_tombstoned" (HTTP 409).


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
}

Routing rules

Routing rules (geo and device targeting, A/B splits, deep links) are managed from the dashboard link editor and are not part of the workspace-API-key surface. The dashboard saves the complete ordered ruleset in one operation-the first matching enabled rule wins at redirect time, and the supported action types are destination_override, ab_split, and deep_link. See Routing rules and preview.


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):

ParameterDescription
short_urlFull short URL to look up.
domain_idDomain UUID.
short_codeShort 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:

ParameterDescription
account_idWorkspace UUID.
limitMax 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 link QR rendering, preset management, saved Static QR records, QR folders, QR-only link analytics, and Retail & GS1 workflows through the same customer API host.

QR API rules

  • QR endpoints require the same workspace API key auth model shown above.
  • Link QR rendering targets an existing Nimriz url_id; link QR remains a view of a short link, not a separate QR object.
  • Saved Static QR endpoints manage fixed QR records in the QR Codes inventory.
  • 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.
  • Retail & GS1 endpoints require both QR API access and Retail & GS1 access. They are available on Professional and Enterprise workspaces.

Available QR endpoints

MethodPathPurpose
POST/api/v1/qr/generateRender a QR asset for an existing link.
GET/api/v1/qr/presetsList QR presets visible to the workspace.
POST/api/v1/qr/presetsCreate a QR preset.
PUT/api/v1/qr/presets/:idUpdate a QR preset.
DELETE/api/v1/qr/presets/:idDelete a QR preset.
GET/api/v1/qr/codesList saved static QR codes.
POST/api/v1/qr/codesCreate a saved static QR code.
PATCH/api/v1/qr/codes/:idUpdate a saved static QR code.
DELETE/api/v1/qr/codes/:idDelete a saved static QR code.
GET/api/v1/qr/codes/:id/assetRender a saved static QR code as PNG or SVG.
GET/api/v1/qr/foldersList QR folders with code counts.
POST/api/v1/qr/foldersCreate a QR folder.
GET/api/v1/qr/retail/productsLoad Retail & GS1 products, packaging variants, Digital Links, generated codes, resolver rules, and validation reports.
POST/api/v1/qr/retail/productsCreate a Retail & GS1 product.
POST/api/v1/qr/retail/packagingCreate a packaging variant.
POST/api/v1/qr/retail/validateValidate a GS1 Digital Link input without creating a record.
POST/api/v1/qr/retail/digital-linksCreate a validated GS1 Digital Link record.
POST/api/v1/qr/retail/codesGenerate a GS1 QR or GS1 DataMatrix asset.
GET/api/v1/qr/retail/codes/:id/assetDownload a generated Retail & GS1 asset.
POST/api/v1/qr/retail/resolver-rulesCreate a GS1 resolver rule.
GET/api/v1/links/:id/qrDownload the link's effective QR asset.
GET/api/v1/links/:id/analyticsReturn link analytics with touch_type=qr_scan by default.

The saved static QR endpoints manage records in your QR inventory. Static QR codes hold their content directly and are not tracked. Create a code with a name, a payload_type (url, text, phone, email, whatsapp, sms, location, wifi, vcard, mecard, or calendar), and a payload_json of the validated fields for that type. The same validation as the dashboard applies. There is no unauthenticated public generation API.

Retail & GS1 endpoints manage product-backed GS1 Digital Link records. Nimriz provides standards-aware validation for supported identifiers and generated assets, but it does not assign GTINs or certify retailer, POS, or supply-chain acceptance.

Batch ZIP export for generated Retail & GS1 assets is available through POST /api/exports/jobs with job_kind = "qr_bulk_download" and qr_source = "gs1_retail". See Exports for the request shape.

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_id is required and must belong to a link the API key can access.
  • format can be png or svg. Defaults to svg when omitted.
  • size is clamped to 128-2048. The default is 512.
  • force_regenerate: true bypasses any cached asset and rebuilds the QR output.
  • qr_preset_id is optional.
  • style is 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_default is true, 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.

Retail & GS1 API

Retail & GS1 API calls use the same API key header as the rest of the customer API. They require a Professional or Enterprise workspace with QR API access and Retail & GS1 access.

Create a product:

POST https://api.nimriz.com/api/v1/qr/retail/products
Authorization: Bearer <WORKSPACE_API_KEY>
Content-Type: application/json
{
  "brand": "Acme",
  "name": "Trail Mix",
  "gtin": "09506000134352",
  "target_market": "US"
}

Validate a Digital Link input:

{
  "gtin": "09506000134352",
  "resolver_host": "id.example.com",
  "resolver_path_prefix": "01",
  "batch_lot": "LOT42",
  "expiry": "270630"
}

Successful validation responses include ok, validation errors, warnings, normalizedIdentifiers, canonicalUri, and elementString.

Generate a code:

{
  "digital_link_id": "55555555-5555-5555-5555-555555555555",
  "symbology": "gs1_datamatrix",
  "format": "svg",
  "size": 512,
  "quiet_zone": 4
}

symbology can be gs1_qr or gs1_datamatrix. format can be svg or png.

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:

ParameterDescription
formatpng or svg. Defaults to svg.
sizeOptional size from 128-2048. Defaults to 512.
force_regenerate1, 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:

ParameterDescription
range_daysOptional daily range from 1-365. Defaults to 30.
include_bots0/1 or boolean-like values. Defaults to 0.
touch_typeqr_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

CodeHTTPMeaning
plan_limit403The request exceeds a per-plan object cap (for example QR presets, saved static QR codes, or QR folders).
monthly_quota_exceeded429Monthly link-creation quota exceeded.
slug_reserved403Slug is below the domain's minimum custom-slug length. A reserved system path on a Nimriz domain returns 400.
slug_tombstoned409Slug was recently deleted and is still held. A slug that is simply taken returns 409 with "Slug already exists" and no code field.
domain_disabled403Target domain is inactive.
account_suspended403Account is suspended.
custom_domain_not_ready403Domain is not yet Ready for traffic. The response includes reason_code and per-record checks.
destination_blocked400Destination host is on the blocklist, or outside the allowlist when one is configured. Forbidden schemes and Nimriz-managed hosts are rejected with 400 and a message but no code field.
invalid_expires_at400Expiration timestamp is malformed. A timestamp in the past returns expires_in_past (400).
expiration_required403Domain policy requires an expiration date.
expiration_update_not_allowed403Expiration updates are not available on this plan or domain.
password_not_allowed403Password-protected links are not available on your plan.
feature_not_enabled403The requested feature area (e.g., QR API, destinations, webhooks, conversion tracking) is not available on your plan.

Retry guidance

  • Do not retry 4xx errors immediately-they indicate input problems or policy failures that will not resolve with a retry.
  • Do retry 429, 502, 503, 504 with exponential backoff.
  • For bulk import jobs, use POST /api/shorten/bulk with stable idempotency_key values so retries are safe.

Related guides

Related next steps

Ready to test this setup?

Create an account to try the workflow, or compare plans when the setup needs higher limits, integrations, or team controls.