For developers

API documentation

Create, manage, and pull analytics for your links programmatically with the Quik.mn REST API.

All services

Every Quik.mn product — via REST API and the web.

Short link
REST API
QR code
REST API
Email Counter
REST API
Countdown
REST API
Quik Bio
REST API
Menu QR
REST API
Email signatures
REST API
UTM builder
Free tools

Base URL

All endpoints start from the following base URL:

https://quik.mn/api/v1

Authentication

On every request, include the API key from your dashboard in the Authorization header:

Authorization: Bearer qk_live_...

Never share your key with anyone. If it leaks, regenerate it from your dashboard.

Endpoints

Short link
POST /api/v1/links Create a new short link
GET /api/v1/links List your links
GET /api/v1/links/{id} Get a single link
PATCH /api/v1/links/{id} Update a link
DELETE /api/v1/links/{id} Delete a link
POST /api/v1/links/{id}/extend Extend expiry — body: {"days": 365}
QR code
GET /api/v1/links/{id}/qr Get a QR code — ?format=png|svg&size=300&fg=241210&bg=FFFFFF
Email Counter
POST /api/v1/timers Create an Email Counter — response: gif_url + embed_html
GET /api/v1/timers Counter list
GET /api/v1/timers/{id} Counter details
PATCH /api/v1/timers/{id} Edit counter
DELETE /api/v1/timers/{id} Delete counter
Countdown pages
POST /api/v1/countdowns Create a Countdown page — response: page_url
GET /api/v1/countdowns Page list
GET /api/v1/countdowns/{id} Page details
PATCH /api/v1/countdowns/{id} Edit page
DELETE /api/v1/countdowns/{id} Delete page
Quik Bio
POST /api/v1/bio-pages Create a Bio page — response: page_url (avatar upload is web-only)
GET /api/v1/bio-pages List your Bio pages
GET /api/v1/bio-pages/{id} Get a single Bio page — links included
PATCH /api/v1/bio-pages/{id} Update a Bio page
DELETE /api/v1/bio-pages/{id} Delete a Bio page
GET /api/v1/bio-pages/{id}/stats Bio statistics — views and clicks
GET /api/v1/bio-pages/{id}/links List a Bio page's links
POST /api/v1/bio-pages/{id}/links Add a Bio link
PATCH /api/v1/bio-pages/{id}/links/{lid} Update a Bio link
DELETE /api/v1/bio-pages/{id}/links/{lid} Delete a Bio link
Menu QR
POST /api/v1/menus Create a menu — response: page_url
GET /api/v1/menus List your menus
GET /api/v1/menus/{id} Get a single menu — items included
PATCH /api/v1/menus/{id} Update a menu
DELETE /api/v1/menus/{id} Delete a menu
GET /api/v1/menus/{id}/stats Scan statistics — total, 30 days, by table
GET /api/v1/menus/{id}/items List menu items
POST /api/v1/menus/{id}/items Add a menu item — photo upload is web-only
PATCH /api/v1/menus/{id}/items/{iid} Update a menu item
DELETE /api/v1/menus/{id}/items/{iid} Delete a menu item
Email signatures
POST /api/v1/signatures Create a signature — logo accepted only as a URL
GET /api/v1/signatures List your signatures
GET /api/v1/signatures/{id} Get a single signature — signature_html included
PATCH /api/v1/signatures/{id} Update a signature
DELETE /api/v1/signatures/{id} Delete a signature
Account
GET /api/v1/me Current account info

Parameters

POST /api/v1/links — request body fields:

url required The destination URL (http/https).
alias optional Custom short name (letters, digits, - and _; 1–64 characters). Also accepted if sent as "slug".
title optional Title (up to 200 characters).
expires_at optional Expiry time — a future date (e.g. 2026-12-31 23:59:59). Maximum 1 year; defaults to 1 year if omitted. Sending null on PATCH resets it to 1 year.
expire_days optional Or in days: 1/7/30/90/180/365. Simpler than expires_at.
starts_at optional Activation time — UTC datetime (e.g. 2026-08-01 02:00:00). Visitors see a countdown until the scheduled time; must be before expires_at. Send null on PATCH to activate immediately.
on_duplicate optional When an active link to the same URL already exists: "reuse" (default — returns the existing link with a reused:true field) or "create" (creates a new one). A new link is always created when an alias is specified.

GET /api/v1/links — query parameters:

limit Number of items per page (1–100, default 25).
offset Number of rows to skip (pagination).
q Search — matches slug, title, and destination URL.

Error format

Every error returns an HTTP status code (401, 404, 409, 422, 429) and a consistent JSON structure:

{ "error": "alias_taken", "message": "That alias is reserved or already in use." }

Common codes: unauthorized (401), not_found (404), alias_taken (409), invalid_url / invalid_alias / invalid_expires_at / invalid_starts_at (422), rate_limited (429).

Rate limits

60 requests per minute per API key
If you exceed it, a 429 rate_limited response is returned — wait a moment and try again.

Example request

cURL example for creating a short link:

curl -X POST https://quik.mn/api/v1/links \
  -H "Authorization: Bearer qk_live_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/very/long/path",
    "alias": "promo",
    "title": "Spring campaign",
    "expires_at": "2026-12-31 23:59:59"
  }'

Webhook

Register an endpoint in the dashboard's Webhook section and we will POST JSON to your URL whenever a selected event happens. A 2xx response counts as success; otherwise we retry up to 3 times with 1 min → 10 min backoff. After 10 consecutive failures the webhook is automatically disabled.

link.created Fires when a new short link is created (web + API)
link.deleted Fires when a link is deleted
link.expired Fires when a link expires or hits its click limit (daily check)
link.clicks.milestone Fires when clicks cross the 100 / 1,000 / 10,000 threshold — the payload includes a milestone field
timer.expired Fires when an email counter ends
countdown.expired Fires when a countdown page ends
webhook.ping Test event sent by the Test button

Structure of every delivery (example):

{
  "event": "link.created",
  "created_at": "2026-07-18T09:30:00+00:00",
  "data": {
    "link": {
      "id": 42, "slug": "promo", "short_url": "https://quik.mn/promo",
      "long_url": "https://example.com/very/long/path", "title": "Spring campaign",
      "clicks": 0, "active": true, "state": "ok",
      "created_at": "2026-07-18 09:30:00", "expires_at": "2027-07-18 09:30:00"
    }
  }
}

Verifying the signature

Every delivery arrives with these headers: X-Quik-Event (the event name), X-Quik-Signaturesha256=HMAC_SHA256(body, secret). The secret is shown only once, when the webhook is created. ALWAYS verify the signature over the raw request body using a constant-time comparison:

<?php
// PHP — verify the signature over the raw request body
$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_QUIK_SIGNATURE'] ?? '';
$expected  = 'sha256=' . hash_hmac('sha256', $payload, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('invalid signature');
}
$event = json_decode($payload, true);
// $event['event'], $event['data'] ...
http_response_code(200);
// Node.js (Express) — verify the signature over the raw request body
const crypto = require('crypto');

app.post('/quik-webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.get('X-Quik-Signature') || '';
  const expected  = 'sha256=' +
    crypto.createHmac('sha256', secret).update(req.body).digest('hex');

  const a = Buffer.from(expected), b = Buffer.from(signature);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).send('invalid signature');
  }
  const event = JSON.parse(req.body); // event.event, event.data ...
  res.sendStatus(200);
});

Limits: Free 1, Pro 3, Business 10 webhooks. The endpoint must be a publicly reachable http/https URL (private-network addresses are blocked).

Get your API key
Create a key in the API section of your dashboard and get started right away.
Get API key