Integration patterns

Practical guidance for retries, idempotency, server-side calling, and bulk import automation.

Integration patterns

This guide focuses on safe automation patterns for Nimriz: server-side calls, retries, idempotency, and import workflows.

Call Nimriz from your server

Recommended architecture:

  1. Authenticate your user in your own backend or trusted runtime.
  2. Call Nimriz from that trusted backend.
  3. Store Nimriz identifiers such as url_id and short_url in your system.

Do not call control-plane endpoints directly from browsers with privileged credentials.

Prefer stable identifiers

Use:

  • url_id as the durable link identifier
  • domain_id as the durable domain identifier

Do not key your system only by slug. Slugs can change.

Retry rules

Retry these classes of failures:

  • 429 with backoff
  • transient 5xx errors such as 502, 503, or 504
  • network timeouts and temporary upstream failures

Do not blindly retry:

  • validation failures
  • authorization failures
  • policy-driven rejections such as reserved slugs or blocked destinations

Exponential backoff example

async function callWithBackoff(run: () => Promise<Response>) {
	let delayMs = 500;
	for (let attempt = 0; attempt < 4; attempt += 1) {
		const response = await run();
		if (response.ok) return response;
		if (![429, 502, 503, 504].includes(response.status)) return response;
		if (attempt === 3) return response;
		await new Promise((resolve) => setTimeout(resolve, delayMs));
		delayMs *= 2;
	}
	throw new Error('unreachable');
}

Idempotency for imports

For job-style creation, prefer POST /api/shorten/bulk.

Each row should include:

  • client_row_id: your stable row identifier inside the batch
  • idempotency_key: a deterministic key for that exact intended mutation

If the same bulk request is replayed, Nimriz returns the stored per-row result with idempotent: true instead of creating a duplicate link.

Good idempotency-key inputs

Build the key from stable fields such as:

  • import session ID
  • row number or source record ID
  • domain_id
  • long_url
  • custom_slug
  • expires_at

If any of those inputs change, generate a new key.

Bulk import recommendations

  • Keep batches small and ordered.
  • Store per-row outcomes in your own job log.
  • Continue processing valid rows even when some rows fail validation.
  • Re-run only the failed or interrupted rows using the same idempotency keys.

Protected-link handling

If you use password-protected links:

  • only send plaintext passwords from a trusted backend
  • do not log plaintext passwords in your own request logs
  • treat password updates as sensitive mutations, not general-purpose retries

Trusted actor headers

The Nimriz first-party app forwards trusted actor headers for provenance and role-aware enforcement. Third-party integrations usually do not need these headers unless they are part of a tightly controlled internal environment.

If you do use them, send them only from trusted infrastructure and only together with valid control-plane authentication.

Conversion callback pattern

Phase 1 conversion tracking is a signed callback flow, not a browser pixel.

Recommended pattern:

  1. User clicks a short link.
  2. If the destination is safe, Nimriz appends nim_ct to the landing URL.
  3. Your application stores that token on the session, lead, cart, checkout, or order record.
  4. When your backend confirms the real business event, it sends a signed callback to Nimriz.

Use the workspace callback secret from the dashboard integrations screen. Do not use CONTROL_PLANE_API_KEY for conversion events.

Recommended storage points

  • lead forms: save nim_ct on the pending lead or CRM contact
  • checkout flows: save nim_ct on the cart, order, or payment metadata
  • later lifecycle events: reuse your own external_id, order_id, and related_order_id

Event recipes

  • form submit -> lead
    • read nim_ct from the landing URL
    • store it with the pending signup or CRM record
    • after the lead or account is created, send event_name: "lead"
  • checkout success -> sale
    • store nim_ct on the order before payment
    • after payment succeeds, send event_name: "sale" with custom_data.order_id, custom_data.value, and custom_data.currency
  • billing webhook -> refund
    • receive the refund or cancellation webhook in your backend
    • look up the original order or transaction
    • send event_name: "refund" or event_name: "cancellation" with custom_data.related_order_id

Retry guidance for conversions

  • Retry transient 429 and 5xx failures with backoff.
  • Reuse the same idempotency key for true retries of the same business event.
  • Generate a new idempotency key when the underlying business event changes.

Current best practice summary

  • Single create: use POST /api/shorten
  • Imports and replay-safe jobs: use POST /api/shorten/bulk
  • Slug preflight: use POST /api/check-slug
  • Link edits: use the specific update endpoints instead of recreating links
  • Conversion callbacks: capture nim_ct, persist it in your system, and send signed server-to-server callbacks from your backend

Roadmap note

Webhook delivery is available for plans with webhook access. Review Webhooks and keep consumers idempotent from the start.

Conversion tracking is available as an opt-in, signed callback flow on supported plans. Review Conversion tracking before building post-click attribution or revenue callbacks.

Related guides