# ZoLinks Developer API

Programmatic access to ZoLinks smartlinks, short URLs, gated links, QR codes, and webhooks.

- Site: https://zolinks.in
- Docs (interactive): https://zolinks.in/docs
- Get an API key: https://zolinks.in/dashboard/api-keys

## Authentication

All endpoints require a Bearer token in the `Authorization` header. Issue keys at https://zolinks.in/dashboard/api-keys. Keys are prefixed `zk_live_` and are scoped to the issuing account.

```
Authorization: Bearer zk_live_your_api_key_here
```

## Base URL

All endpoints are served from `https://zolinks.in/developers/api/v1`.

## Credits & rate limits

Every successful call costs 1 credit. Buy credits from the dashboard; usage is reported via `GET /credits`. Rate limits are per-key and surface as HTTP 429.

## Error codes

Errors return JSON `{ "error": string, "code": string }`. Common HTTP statuses: 400 (validation), 401 (missing/invalid key), 402 (no credits), 403 (forbidden), 404 (not found), 409 (conflict), 429 (rate limit), 500 (server).

## Endpoints

### GET /credits

Get your current credit balance and lifetime usage. Costs 1 credit per call.

**Response example**

```json
{
  "balance": 974,
  "total_used": 26,
  "total_purchased": 1000,
  "updated_at": "2026-04-29T..."
}
```

**cURL**

```bash
curl https://zolinks.in/developers/api/v1/credits \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/credits", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/credits", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

## Smartlinks

### POST /smartlinks

Create a new smartlink with platform-specific URLs.

**Request body**

- `title` (string, required) — Title of the smartlink
- `slug` (string, required) — URL-friendly slug (unique)
- `artwork_url` (string) — Artwork/cover image URL
- `platforms` (array) — Array of { platform, url } objects

```json
{
  "title": "My New Song",
  "slug": "my-new-song",
  "artwork_url": "https://example.com/cover.jpg",
  "platforms": [
    { "platform": "spotify", "url": "https://open.spotify.com/track/..." },
    { "platform": "apple_music", "url": "https://music.apple.com/..." }
  ]
}
```

**Response example**

```json
{
  "id": "uuid",
  "developer_id": "uuid",
  "title": "My New Song",
  "slug": "my-new-song",
  "artwork_url": "https://example.com/cover.jpg",
  "is_active": true,
  "click_count": 0,
  "created_at": "2026-04-12T...",
  "platforms": [
    { "id": "uuid", "smartlink_id": "uuid", "platform": "spotify", "url": "https://...", "position": 0, "click_count": 0 }
  ]
}
```

**cURL**

```bash
curl -X POST https://zolinks.in/developers/api/v1/smartlinks \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"title":"My New Song","slug":"my-new-song","platforms":[{"platform":"spotify","url":"https://open.spotify.com/track/..."}]}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/smartlinks", {
  method: "POST",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    title: "My New Song",
    slug: "my-new-song",
    platforms: [{ platform: "spotify", url: "https://open.spotify.com/track/..." }]
  })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.post("https://zolinks.in/developers/api/v1/smartlinks", {
  title: "My New Song",
  slug: "my-new-song",
  platforms: [{ platform: "spotify", url: "https://open.spotify.com/track/..." }]
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /smartlinks

List all smartlinks owned by the calling API key, sorted by created_at descending. Pagination is offset-based; total reflects the full owned set so you can build pagers without extra requests.

**Query parameters**

- `page` (integer) — 1-based page number. Values < 1 are clamped to 1. Default: 1.
- `per_page` (integer) — Results per page. Clamped to the inclusive range [1, 100]. Default: 20.

**Response fields**

- `smartlinks` (array) — Smartlink rows for the requested page (see body below). Platforms are NOT included here — call GET /v1/smartlinks/:id for the full record.
- `total` (integer) — Total number of smartlinks owned by your account (across all pages).
- `page` (integer) — Echo of the resolved page parameter.
- `per_page` (integer) — Echo of the resolved per_page parameter.

**Response example**

```json
{
  "smartlinks": [
    {
      "id": "1f8c8e2a-…",
      "developer_id": "9a2b3c4d-…",
      "title": "My New Song",
      "slug": "my-new-song",
      "artwork_url": "https://cdn.zolinks.in/smartlink-artwork/…/cover.jpg",
      "is_active": true,
      "click_count": 42,
      "created_at": "2026-04-12T08:30:12.000Z"
    }
  ],
  "total": 27,
  "page": 1,
  "per_page": 20
}
```

**cURL**

```bash
curl "https://zolinks.in/developers/api/v1/smartlinks?page=1&per_page=20" \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/smartlinks?page=1&per_page=20", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/smartlinks", {
  params: { page: 1, per_page: 20 },
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /smartlinks/:id

Fetch one smartlink by id along with the full ordered list of platform destinations. Each platform row carries its own click_count so you can render a per-destination breakdown without a separate analytics call.

**Query parameters**

- `id` (uuid (path), required) — Smartlink id. 404 if not found OR not owned by the calling API key.

**Response fields**

- `id` (uuid) — Smartlink id.
- `title` (string) — Display title (≤255 chars).
- `slug` (string) — URL slug, unique across the entire smartlinks namespace.
- `artwork_url` (string | null) — Optional cover artwork URL.
- `is_active` (boolean) — If false, the public smartlink page returns 404 and clicks are ignored.
- `click_count` (integer) — Total clicks across all platforms (sum of platforms[].click_count).
- `created_at` (timestamp) — ISO-8601 UTC creation timestamp.
- `platforms` (array) — Ordered by position ascending. Each row: { id, platform, url, position, click_count }.

**Response example**

```json
{
  "id": "1f8c8e2a-…",
  "title": "My New Song",
  "slug": "my-new-song",
  "artwork_url": "https://cdn.zolinks.in/smartlink-artwork/…/cover.jpg",
  "is_active": true,
  "click_count": 42,
  "created_at": "2026-04-12T08:30:12.000Z",
  "platforms": [
    { "id": "p1-…", "platform": "spotify",     "url": "https://open.spotify.com/track/…",       "position": 0, "click_count": 10 },
    { "id": "p2-…", "platform": "apple_music", "url": "https://music.apple.com/…",              "position": 1, "click_count": 8  },
    { "id": "p3-…", "platform": "youtube",     "url": "https://youtu.be/…",                     "position": 2, "click_count": 24 }
  ]
}
```

**cURL**

```bash
curl https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### PUT /smartlinks/:id

Update a smartlink's title, slug, artwork, active status, or platforms. Providing platforms replaces the entire list.

**Request body**

- `title` (string) — New title
- `slug` (string) — New slug
- `artwork_url` (string) — New artwork URL (null to remove)
- `is_active` (boolean) — Enable or disable the smartlink
- `platforms` (array) — Replacement array of { platform, url } objects

```json
{
  "title": "Updated Song Title",
  "platforms": [
    { "platform": "spotify", "url": "https://open.spotify.com/track/..." },
    { "platform": "youtube", "url": "https://youtube.com/watch?v=..." }
  ]
}
```

**cURL**

```bash
curl -X PUT https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"title":"Updated Song Title"}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ title: "Updated Song Title" })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.put("https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID", {
  title: "Updated Song Title"
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### DELETE /smartlinks/:id

Delete a smartlink and all its platform URLs. Returns { "success": true }.

**Response example**

```json
{ "success": true }
```

**cURL**

```bash
curl -X DELETE https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID", {
  method: "DELETE",
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.delete("https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### POST /smartlinks/:id/click

Track a click on a smartlink. If a platform is supplied, BOTH the smartlink's total click_count AND that platform's per-destination click_count are atomically incremented; otherwise only the smartlink total is incremented. Fires the smartlink.clicked webhook with { smartlink_id, platform } to every active subscription.

**Query parameters**

- `id` (uuid (path), required) — Smartlink id. 404 if not found.

**Request body**

- `platform` (string) — Optional. Platform key as stored on the smartlink (e.g. 'spotify', 'apple_music', 'youtube'). If omitted, only the smartlink's total counter increments — useful when you don't yet know which destination the user will pick.

```json
{
  "platform": "spotify"
}
```

**Response fields**

- `success` (boolean) — Always true on a 200 response.
- `clicks` (integer) — The smartlink's NEW total click_count after this increment (sum across all platforms).

**Response example**

```json
{
  "success": true,
  "clicks": 43
}
```

**cURL**

```bash
curl -X POST https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID/click \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"platform":"spotify"}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID/click", {
  method: "POST",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ platform: "spotify" })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.post(
  "https://zolinks.in/developers/api/v1/smartlinks/SMARTLINK_UUID/click",
  { platform: "spotify" },
  { headers: { Authorization: "Bearer zk_live_your_api_key_here" } }
);
```

## Short URLs

### POST /shorturls

Create a short URL. Returns the resolved public URL at https://zolinks.in/s/d/<slug>. Costs 1 credit.

**Request body**

- `target_url` (string, required) — Destination URL (http or https)
- `slug` (string) — Optional custom slug (4–32 alnum/-/_). Auto-generated if omitted.
- `title` (string) — Internal label
- `expires_at` (ISO 8601) — Optional expiry timestamp
- `password` (string) — Optional password — stored as a salted hash

```json
{
  "target_url": "https://example.com/some/long/path",
  "title": "Summer sale"
}
```

**Response example**

```json
{
  "id": "uuid",
  "slug": "Ab12Cd3",
  "short_url": "https://zolinks.in/s/d/Ab12Cd3",
  "target_url": "https://example.com/some/long/path",
  "is_active": true,
  "click_count": 0,
  "created_at": "2026-06-12T..."
}
```

**cURL**

```bash
curl -X POST https://zolinks.in/developers/api/v1/shorturls \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"target_url":"https://example.com/some/long/path"}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/shorturls", {
  method: "POST",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ target_url: "https://example.com/some/long/path" })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.post("https://zolinks.in/developers/api/v1/shorturls", {
  target_url: "https://example.com/some/long/path"
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /shorturls

List short URLs owned by the calling API key, paginated.

**Query parameters**

- `page` (integer) — 1-based page number. Default 1.
- `per_page` (integer) — Clamped to [1, 100]. Default 20.

**Response example**

```json
{
  "shorturls": [
    { "id": "uuid", "slug": "Ab12Cd3", "short_url": "https://zolinks.in/s/d/Ab12Cd3", "target_url": "https://...", "click_count": 42, "is_active": true, "created_at": "2026-06-12T..." }
  ],
  "total": 1,
  "page": 1,
  "per_page": 20
}
```

**cURL**

```bash
curl "https://zolinks.in/developers/api/v1/shorturls?page=1&per_page=20" \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/shorturls?page=1&per_page=20", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/shorturls", {
  params: { page: 1, per_page: 20 },
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /shorturls/:id

Fetch one short URL by id.

**cURL**

```bash
curl https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### PUT /shorturls/:id

Update title, expiry, active status, or password.

```json
{
  "title": "Updated",
  "is_active": false,
  "expires_at": "2026-12-31T23:59:59Z"
}
```

**cURL**

```bash
curl -X PUT https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"is_active":false}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ is_active: false })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.put("https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID", {
  is_active: false
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### DELETE /shorturls/:id

Delete a short URL. Returns { "success": true }.

**cURL**

```bash
curl -X DELETE https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID", {
  method: "DELETE",
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.delete("https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /shorturls/:id/analytics

Daily click time-series, top referrers, and top countries for a short URL.

**Query parameters**

- `days` (integer) — Window in days, 1–90. Default 30.

**Response example**

```json
{
  "id": "uuid",
  "total_clicks": 142,
  "time_series": [ { "date": "2026-06-01", "clicks": 5 } ],
  "top_referrers": [ { "source": "twitter.com", "count": 30 } ],
  "top_countries": [ { "country": "IN", "count": 88 } ]
}
```

**cURL**

```bash
curl "https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID/analytics?days=30" \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID/analytics?days=30", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/shorturls/SHORTURL_UUID/analytics", {
  params: { days: 30 },
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

## Gated Links

### POST /gated-links

Create a gated link. Public URL is https://zolinks.in/g/d/<slug>. mode 'email' is available on all plans; mode 'payment' requires the Business plan and a configured payment gateway.

**Request body**

- `title` (string, required) — Display title
- `slug` (string) — Optional custom slug
- `destination_url` (string, required) — URL revealed after unlock
- `mode` ('email' | 'payment') — Unlock method. Default 'email'.
- `price_inr` (number) — Price in paise (mode=payment)
- `price_usd` (number) — Price in cents (mode=payment)
- `max_unlocks` (integer) — Optional cap on total unlocks
- `expires_at` (ISO 8601) — Optional expiry

```json
{
  "title": "Free eBook",
  "destination_url": "https://example.com/ebook.pdf",
  "mode": "email"
}
```

**Response example**

```json
{
  "id": "uuid",
  "slug": "free-ebook",
  "public_url": "https://zolinks.in/g/d/free-ebook",
  "mode": "email",
  "is_active": true,
  "view_count": 0,
  "unlock_count": 0
}
```

**cURL**

```bash
curl -X POST https://zolinks.in/developers/api/v1/gated-links \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"title":"Free eBook","destination_url":"https://example.com/ebook.pdf","mode":"email"}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/gated-links", {
  method: "POST",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    title: "Free eBook",
    destination_url: "https://example.com/ebook.pdf",
    mode: "email"
  })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.post("https://zolinks.in/developers/api/v1/gated-links", {
  title: "Free eBook",
  destination_url: "https://example.com/ebook.pdf",
  mode: "email"
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /gated-links

List gated links owned by the calling API key, paginated.

**cURL**

```bash
curl "https://zolinks.in/developers/api/v1/gated-links?page=1&per_page=20" \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/gated-links?page=1&per_page=20", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/gated-links", {
  params: { page: 1, per_page: 20 },
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /gated-links/:id

Fetch one gated link by id, including counters.

**cURL**

```bash
curl https://zolinks.in/developers/api/v1/gated-links/GATED_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### PUT /gated-links/:id

Update title, destination, pricing, caps, or active status.

```json
{
  "title": "Updated",
  "is_active": true
}
```

**cURL**

```bash
curl -X PUT https://zolinks.in/developers/api/v1/gated-links/GATED_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"title":"Updated"}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ title: "Updated" })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.put("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID", {
  title: "Updated"
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### DELETE /gated-links/:id

Delete a gated link and its unlocks. Returns { "success": true }.

**cURL**

```bash
curl -X DELETE https://zolinks.in/developers/api/v1/gated-links/GATED_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID", {
  method: "DELETE",
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.delete("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /gated-links/:id/unlocks

List unlock records (email captures and successful payments) for a gated link.

**Query parameters**

- `page` (integer) — 1-based page. Default 1.
- `per_page` (integer) — Clamped [1, 100]. Default 50.

**cURL**

```bash
curl "https://zolinks.in/developers/api/v1/gated-links/GATED_UUID/unlocks?page=1" \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID/unlocks?page=1", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID/unlocks", {
  params: { page: 1 },
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /gated-links/:id/analytics

Daily views/unlocks time-series for a gated link.

**Query parameters**

- `days` (integer) — Window 1–90. Default 30.

**Response example**

```json
{
  "id": "uuid",
  "view_count": 1280,
  "unlock_count": 96,
  "time_series": [ { "date": "2026-06-01", "views": 42, "unlocks": 3 } ]
}
```

**cURL**

```bash
curl "https://zolinks.in/developers/api/v1/gated-links/GATED_UUID/analytics?days=30" \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID/analytics?days=30", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/gated-links/GATED_UUID/analytics", {
  params: { days: 30 },
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

## QR Codes

### POST /qr

Generate a QR image on the fly without persisting anything. Responds directly with the binary/text image. Costs 1 credit per call.

**Request body**

- `data` (string, required) — Payload to encode (URL or text)
- `format` ('svg' | 'png') — Default 'svg'
- `size` (integer) — Pixels per side, 64–2048. Default 512.
- `fg` (string) — Foreground hex (e.g. '#000000')
- `bg` (string) — Background hex

```json
{
  "data": "https://zolinks.in",
  "format": "svg",
  "size": 512
}
```

**Response example**

```json
<svg xmlns="http://www.w3.org/2000/svg" ...>...</svg>
```

**cURL**

```bash
curl -X POST https://zolinks.in/developers/api/v1/qr \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"data":"https://zolinks.in","format":"svg"}' \
  -o qr.svg
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/qr", {
  method: "POST",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ data: "https://zolinks.in", format: "svg" })
});
const svg = await res.text();
```

**Node.js (axios)**

```js
const axios = require("axios");
const fs = require("fs");

const res = await axios.post("https://zolinks.in/developers/api/v1/qr", {
  data: "https://zolinks.in", format: "png", size: 512
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" },
  responseType: "arraybuffer"
});
fs.writeFileSync("qr.png", res.data);
```

### POST /qr/codes

Save a QR template so it can be rendered repeatedly without re-specifying styling.

```json
{
  "name": "Homepage QR",
  "data": "https://zolinks.in",
  "fg": "#000000",
  "bg": "#ffffff"
}
```

**cURL**

```bash
curl -X POST https://zolinks.in/developers/api/v1/qr/codes \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name":"Homepage QR","data":"https://zolinks.in"}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/qr/codes", {
  method: "POST",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ name: "Homepage QR", data: "https://zolinks.in" })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.post("https://zolinks.in/developers/api/v1/qr/codes", {
  name: "Homepage QR", data: "https://zolinks.in"
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /qr/codes

List saved QR templates.

**cURL**

```bash
curl https://zolinks.in/developers/api/v1/qr/codes \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/qr/codes", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/qr/codes", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /qr/codes/:id

Fetch a saved QR template by id. Add /render to fetch a rendered image instead.

**cURL**

```bash
curl https://zolinks.in/developers/api/v1/qr/codes/QR_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/qr/codes/QR_UUID", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/qr/codes/QR_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### PUT /qr/codes/:id

Update a saved QR template's name, data, or styling.

```json
{
  "name": "Updated QR",
  "fg": "#111827"
}
```

**cURL**

```bash
curl -X PUT https://zolinks.in/developers/api/v1/qr/codes/QR_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name":"Updated QR"}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/qr/codes/QR_UUID", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({ name: "Updated QR" })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.put("https://zolinks.in/developers/api/v1/qr/codes/QR_UUID", {
  name: "Updated QR"
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### DELETE /qr/codes/:id

Delete a saved QR template. Returns { "success": true }.

**cURL**

```bash
curl -X DELETE https://zolinks.in/developers/api/v1/qr/codes/QR_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/qr/codes/QR_UUID", {
  method: "DELETE",
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.delete("https://zolinks.in/developers/api/v1/qr/codes/QR_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

## Webhooks

### POST /webhooks

Register a new webhook endpoint.

**Request body**

- `url` (string, required) — Your webhook endpoint URL
- `events` (string[], required) — Array of event types, e.g. ["smartlink.clicked"]

```json
{
  "url": "https://your-app.com/webhooks/zolinks",
  "events": ["smartlink.clicked"]
}
```

**Response example**

```json
{
  "id": "uuid",
  "url": "https://your-app.com/webhooks/zolinks",
  "events": ["smartlink.clicked"],
  "secret": "whsec_...",
  "message": "Store the secret securely..."
}
```

**cURL**

```bash
curl -X POST ${BASE_PLACEHOLDER}/webhooks \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-app.com/webhook","events":["smartlink.clicked"]}'
```

**JavaScript (fetch)**

```js
const res = await fetch("${BASE_PLACEHOLDER}/webhooks", {
  method: "POST",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    url: "https://your-app.com/webhook",
    events: ["smartlink.clicked"]
  })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.post("${BASE_PLACEHOLDER}/webhooks", {
  url: "https://your-app.com/webhook",
  events: ["smartlink.clicked"]
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /webhooks

List all your registered webhooks.

**Response example**

```json
[
  {
    "id": "uuid",
    "url": "https://your-app.com/webhook",
    "events": ["smartlink.clicked"],
    "is_active": true,
    "created_at": "2026-04-02T..."
  }
]
```

**cURL**

```bash
curl https://zolinks.in/developers/api/v1/webhooks \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/webhooks", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/webhooks", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### GET /webhooks/:id

Fetch a single webhook by ID.

**cURL**

```bash
curl https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID", {
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.get("https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### PUT /webhooks/:id

Update a webhook's URL, events, or active status.

```json
{
  "url": "https://new-url.com/webhooks",
  "is_active": false
}
```

**cURL**

```bash
curl -X PUT https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://new-url.com/webhooks","is_active":false}'
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID", {
  method: "PUT",
  headers: {
    "Authorization": "Bearer zk_live_your_api_key_here",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    url: "https://new-url.com/webhooks",
    is_active: false
  })
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.put("https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID", {
  url: "https://new-url.com/webhooks",
  is_active: false
}, {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### DELETE /webhooks/:id

Delete a webhook. Returns { "success": true }.

**Response example**

```json
{ "success": true }
```

**cURL**

```bash
curl -X DELETE https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID", {
  method: "DELETE",
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.delete("https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID", {
  headers: { Authorization: "Bearer zk_live_your_api_key_here" }
});
```

### POST /webhooks/:id/test

Enqueue a synthetic webhook.test delivery so you can verify your endpoint signature/handler.

**Response example**

```json
{
  "success": true,
  "message": "Test delivery enqueued.",
  "payload": { "test": true, "message": "...", "timestamp": "..." }
}
```

**cURL**

```bash
curl -X POST https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID/test \
  -H "Authorization: Bearer zk_live_your_api_key_here"
```

**JavaScript (fetch)**

```js
const res = await fetch("https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID/test", {
  method: "POST",
  headers: { "Authorization": "Bearer zk_live_your_api_key_here" }
});
const data = await res.json();
```

**Node.js (axios)**

```js
const axios = require("axios");

const { data } = await axios.post(
  "https://zolinks.in/developers/api/v1/webhooks/WEBHOOK_UUID/test",
  null,
  { headers: { Authorization: "Bearer zk_live_your_api_key_here" } }
);
```