Conventions
These rules apply to every endpoint in the API. Reading them once will save you
from surprises on individual resources.
JSON in, JSON out
Send Content-Type: application/json on requests with a body. Responses are
always JSON.
Field naming
Request bodies accept either camelCase or snake_case — targetUrl and
target_url are equivalent. Responses include both forms for each field,
plus an id, so you can read whichever your code prefers:
{
"id": "b1a2…",
"shortUrl": "https://zngl.ink/spring-sale",
"short_url": "https://zngl.ink/spring-sale",
"targetUrl": "https://example.com/spring",
"target_url": "https://example.com/spring",
"clickCount": 412,
"click_count": 412
}
Identifiers
All resource ids are UUID strings. A link's slug is its public identifier and
is unique per domain, but endpoints address links by id. Build public URLs from
the shortUrl field rather than concatenating a host and slug yourself.
Pagination
List endpoints are offset-based:
| Parameter | Meaning | Default | Range |
|---|---|---|---|
limit |
Page size | 50 |
1–200 |
offset |
Rows to skip | 0 |
0+ |
A list response wraps the rows with the total count and the echoed paging
window:
{
"data": [ { "id": "…" }, { "id": "…" } ],
"total": 137,
"limit": 50,
"offset": 0
}
To page through everything, keep requesting with offset += limit until
offset + len(data) >= total.
Filtering and search
| Parameter | Purpose |
|---|---|
source |
app (default), crm (links ZingaConnect minted for campaigns) or all |
status |
active, archived or disabled |
q |
Substring match on a link's slug or title |
days |
The analytics window on the stats endpoint (1–365, default 30) |
Example:
curl "https://api-v1.zingasuite.com/papi/v1/links?q=spring&limit=20" \
-H "Authorization: Bearer zk_live_xxx"
Timestamps
Timestamps are ISO-8601 in UTC. Where present, createDate / updateDate (and
resource-specific fields such as placedAt) reflect create and last-modified
times.
Idempotency & retries
Writes are not automatically deduplicated. Creating a link with a slug that is
already taken returns 409 slug_taken rather than a second link, so passing your
own deterministic slug (for example order-1042) makes a retry safe; a create
with no slug generates a fresh one every time and would leave duplicates behind.