API

Every link, over HTTP. No dashboard required.

Create, update, and delete links from your own code. Clean JSON, one Bearer key, and an OpenAPI spec you can run in the browser.

Auth Bearer · pk_ keys
Spec OpenAPI 3.1
Format JSON in, JSON out
request
POST /api/v1/links
Authorization: Bearer pk_a1b2…
Content-Type: application/json
{
"destination": "https://acme.com/launch",
"slug": "launch",
"tags": ["q3"]
}
response 201 Created
{
"id": 482,
"slug": "launch",
"short_url": "pcol.ink/launch",
"click_count": 0
}
OpenAPI 3.1
keys hashed at rest
How it works

Three steps. Key, request, JSON.

Create a key, send a request, get a link. It shows up in your dashboard the moment you do.

1
mint a key
New API key
pk_a1b2c3d4e5f6g7h8 copy
shown once · store it now
hashed on save

Create a key.

Admins mint keys under API keys. The token shows once, then only its prefix. We store a hash, never the key.

2
send a request
curl -X POST \
pcol.ink/api/v1/links \
-H "Authorization: Bearer pk_…" \
-d '{"destination":"…"}'
any HTTP client

Send a request.

Pass the key as a Bearer token and POST JSON to /api/v1/links. Any HTTP client works.

3
get json back
200 OK
{
"short_url":
"pcol.ink/launch",
"is_active": true
}
live in the dashboard

Get a link back.

The response is the whole link, short URL included. Live at once, with the same analytics, routing, and protection as the rest.

Under the hood

Plain REST. No surprises.

No GraphQL, no SDK, no webhooks to wire up. Standard verbs, standard JSON, real status codes.

01

Full CRUD on your links.

Create, list, fetch, update, and delete, on the verbs you expect. Everything lives under /api/v1/links.

POST/links
GET/links · /links/{id}
PATCH/links/{id}
DEL/links/{id}
02

Bearer keys, hashed at rest.

A pk_ token in the header. Shown once, stored only as a hash, up to five per workspace. Revoke one without touching the rest.

pk_a1b2c3d4 prefix only
hashed shown once revocable
03

Everything the editor can set.

One payload: destination, domain, slug, title, tags, notes, routing rules, and a password. Skip the slug and we make one.

destination domain slug tags routing_rules password + more
04

Paginated, filterable lists.

Page through every link and filter by tag or domain. Each response carries its own pagination.

{
"data": [ … 20 links ],
"pagination": { "page": 1, "total": 148 }
}
05

Real status codes.

One error shape, the right code behind it. 401, 404, 409, 422, 429.

{ "error": {
"code": "slug_taken",
"message": "…" } }
401 404 409 422 429
06

Scoped to your workspace.

A key sees its own account's links. Nothing else, ever.

pk_a1b2 your links others
What people build with it

Links, on autopilot.

What teams build once making links by hand stops scaling.

Bulk from a script.

Loop a spreadsheet and POST a link per row. A thousand campaign URLs in one run.

A link per record.

Mint a link with every new order or invoice, and store the short URL back on the record.

Shorten on publish.

Wire it into your CMS so every post ships with a branded short link.

Tidy up on a schedule.

List by tag from a cron job and DELETE the stale ones.

The fine print

Specs, in plain numbers.

Auth Bearer pk_ In the Authorization header. Hashed at rest, shown once.
Endpoints 5 on links Create, list, get, update, delete. The whole link lifecycle.
Spec 3.1 OpenAPI A published spec with live docs you can call from the browser.
Keys 5 per workspace Mint, name, and revoke them independently.

Make your first link in one request.

Grab a key, open the docs, and POST. That's the whole setup.