Simple Click Tracker Help
Learn more Log in

REST API

Connect SCT Pro to other software, including Pabbly Connect: keys, links, webhooks, events, limits and errors.

The REST API lets other software work with your SCT Pro account. It can create links, look them up, and change where they go. It can also tell another app when a link breaks, a split test picks a winner, or a link reaches a click milestone.

This page is for whoever is setting up the connection, and some of it is technical. If you use Zapier or n8n, you don't need it: see Zapier or n8n instead.

Before you start

  • A plan that includes integrations. Open Integrations. If the REST API box says REST API isn't included in your plan, choose See plans to upgrade first.
  • Owner or admin access. Only the account owner and team admins can see Integrations and create keys. See Team collaboration.

Create a REST API key

  1. Open Integrations and scroll to the REST API box.
  2. Click Create REST API Key.
  3. Give it a name, and choose what it can do: Create links and Update link destinations. A key can always read your links. It can never delete them.
  4. Set an expiration date if you want the key to stop working by itself. This is optional.
  5. Click Create Key and copy the key. It is shown only once. It starts with api_.

Treat the key like a password. It works for your whole account, so keep it out of web pages and public code. If a key leaks, click Revoke in the REST API box. It stops working right away, and its webhooks turn off.

Zapier, n8n, MCP and Connect keys don't work with the REST API, and REST API keys don't work with them.

Making requests

Every address on this page starts with this base URL:

https://app.simpleclicktracker.com/api/v1/rest

Send your key in the Authorization header as a Bearer token. If your tool can't do that, the X-API-Key header also works. Send request bodies as JSON.

curl https://app.simpleclicktracker.com/api/v1/rest/me \
  -H "Authorization: Bearer api_your_key"

Use this call to test a key. It returns the account the key belongs to:

{"data": {"id": 42, "name": "Pat Tester", "email": "pat@example.com"}}

Responses and errors

Successful responses put the result in data. Errors have a message you can show to a person:

{"error": {"message": "That link was not found in your account."}}
StatusMeaning
200, 201It worked. 201 means something was created.
401The key is missing, wrong, expired or revoked, or the account isn't active.
403The plan doesn't include integrations, or the key doesn't have that permission.
404That address doesn't exist, or the item isn't in this account.
422The request couldn't be accepted. The message says why. This includes reaching your plan's link limit.
429Too many requests. Wait for the number of seconds in the Retry-After header.

Limits

  • 120 requests a minute for each key.
  • 20 failed keys a minute from one address. After that, requests from that address get 429 until the minute is up.
  • 100 webhooks and automations for each account. Zaps and n8n triggers count toward this too.

A link looks like this in every response:

{
  "id": 123,
  "name": "Spring sale",
  "type": "standard",
  "url": "https://example.com/offer",
  "path": "spring",
  "domain_id": 7,
  "domain": "go.example.com",
  "group_id": null,
  "short_url": "https://go.example.com/spring",
  "is_archived": false,
  "total_clicks": 1003,
  "unique_clicks": 742
}

GET /links: list or find links

With no search, this returns your links a page at a time, newest first.

Query parameterWhat it does
pagePage number. Starts at 1.
per_pageLinks on each page. Default 25, maximum 100.
domain_idOnly links on this domain.
pathSearch: the exact path.
nameSearch: part of the name.
{"data": [ ... ], "meta": {"page": 1, "per_page": 25, "total": 3}}

A search using path or name returns up to 25 matches, with no meta and no paging. An empty data list means nothing matched, so you can search first and create the link if it isn't there.

GET /links/{id}: read one link

Returns one link in data, or 404 if it isn't in your account.

POST /links: create a link

Creates a standard link. The key needs the Create links permission.

FieldRequiredWhat it does
nameYesA label for you.
urlYesWhere the link sends visitors.
pathNoThe part after your domain. Leave it out and SCT Pro makes one.
domain_idOnly with more than one domainFrom GET /domains.
group_idNoFrom GET /groups.
curl -X POST https://app.simpleclicktracker.com/api/v1/rest/links \
  -H "Authorization: Bearer api_your_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Spring sale", "url": "https://example.com/offer", "path": "spring"}'

Your plan's link limit applies, and so do the same checks as creating a link in SCT Pro.

PATCH /links/{id}: change a destination

Send {"url": "https://example.com/new-offer"} to change where a standard link goes. This is the only field you can change. The key needs the Update link destinations permission. Split tests and rotators send visitors to several places, so edit those in SCT Pro.

Domains and groups

GET /domains and GET /groups return the choices for domain_id and group_id, as a list of {"id": 7, "name": "go.example.com"} in data.

Webhooks

A webhook tells SCT Pro to send an event to an address of yours when something happens.

POST /webhooks: start a webhook

FieldRequiredWhat it does
eventYesOne of the webhook events.
target_urlYesWhere to send events. It must be a public https:// address, and it can't be an SCT Pro address or one of your short link domains.
options.link_idNoWatch one link. Leave it out to watch all your links.
options.milestone_clicksFor click.milestoneThe number of clicks to watch for.
options.click_typeNototal (the default) or unique, for click.milestone.
send_sampleNoSet to true to also send one test event, usually within about a minute. Useful when a tool is waiting to capture a webhook.
curl -X POST https://app.simpleclicktracker.com/api/v1/rest/webhooks \
  -H "Authorization: Bearer api_your_key" \
  -H "Content-Type: application/json" \
  -d '{"event": "link.broken", "target_url": "https://example.com/my-hook", "send_sample": true}'

The response is {"data": {"id": 55}}. Keep the id so you can remove the webhook later. Each call adds a new webhook, even for an address you've already used, so one address can watch two different milestones. Calling it twice with the same settings sends each event twice.

GET /webhooks/{id}: check a webhook

Returns id, event and target_url. A 404 means it was removed or turned off, so start a new one.

DELETE /webhooks/{id}: remove a webhook

Returns {"data": {"deleted": true}}.

GET /webhooks/samples/{event}: see example events

Returns up to three recent events of that type from your account, or one made-up example with an id of 0 if there are none yet. Use it to see the fields without waiting for a real event.

Webhook events

Every event has an id, the event name and an occurred_at time, plus these fields:

link.broken
A destination failed its daily check two days in a row. Fields: link, broken_url, reason, status_code, broken_since, clicks_last_24h. See Broken link monitoring.
link.recovered
A broken destination passed a later check. Fields: link, url, recovered_at.
split.winner
A split test has a winner. Fields: link, winner, runner_up, method (auto_winner, conversion_race or manual), picked_at. A winner you pick yourself is sent only if you choose Send when SCT Pro asks.
click.milestone
A link reached the number of clicks you set. Fields: link, milestone, click_type, total_clicks, unique_clicks, reached_at. Each link fires once per webhook. Links already past the number when you start the webhook are skipped.

Here is a link.broken event:

{
  "id": 981,
  "event": "link.broken",
  "link": {"id": 123, "name": "Spring sale review", "short_url": "https://go.example.com/spring-sale"},
  "broken_url": "https://example.com/offer",
  "reason": "The page was not found (404).",
  "status_code": 404,
  "broken_since": "2026-10-22T09:00:00Z",
  "clicks_last_24h": 57,
  "occurred_at": "2026-10-23T09:00:00Z"
}

Test events from send_sample also have "is_test": true, and their link and numbers are made up. Check for this if your workflow changes something.

How webhooks are delivered

  • SCT Pro sends a POST with a JSON body. Your address should answer with any 2xx status.
  • If it doesn't, SCT Pro tries again after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours. A retried event has the same id, so use it to skip events you've already handled.
  • After 50 failed deliveries in a row, the webhook turns off and the account owner gets an email.
  • If your address answers 410 Gone, the webhook turns off right away.
  • While an account is suspended, its webhooks send nothing, and events waiting to be sent are dropped. Webhooks start sending again when the account is active, but events from that time aren't sent later.
  • Requests aren't signed, so treat your webhook address like a password and make it hard to guess. Most automation tools already give you an address with a long random part.

Using the API with Pabbly Connect

Simple Click Tracker isn't listed as an app inside Pabbly Connect yet. You can still connect the two today using Pabbly's own API and webhook tools.

  • To do something in SCT Pro: add a step with API by Pabbly, and use the address and fields from Links. Add the header Authorization with the value Bearer api_your_key.
  • To start a workflow from SCT Pro: use Webhooks by Pabbly as the trigger and copy its webhook address. Then call POST /webhooks once with that address as target_url and send_sample set to true, so Pabbly has a test event to capture.

Building the app in Pabbly's developer platform

These are the settings for anyone building the Simple Click Tracker app in Pabbly Connect:

Pabbly settingUse
AuthenticationBearer Token, using a REST API key from the Integrations page
App auth validatorGET https://app.simpleclicktracker.com/api/v1/rest/me, which answers 401 for a missing or bad key
TriggersWebhooks Setup by API Request: POST /webhooks with the Pabbly address as target_url
Delete webhookDELETE /webhooks/{id}, using the id from the subscribe response
ActionsPOST /links, PATCH /links/{id}, GET /links, with a JSON body
DropdownsGET /domains, GET /groups, GET /links

What the webhook statuses mean

The REST API box on Integrations lists your webhooks.

Waiting for the first event
The webhook is on. Nothing has happened yet that matches it.
Last event delivered (date)
Working normally.
Failing: (reason)
The last delivery didn't get a 2xx answer. SCT Pro keeps trying. Check that your address is working.
Turned off in the receiving app
Your address answered 410 Gone. Start a new webhook if you still need it.
Turned off after 50 failed deliveries in a row
Fix the problem at your address, then start a new webhook.
Turned off: your plan no longer includes integrations
Upgrade your plan, then start a new webhook.
Turned off: its REST API key was revoked
Create a new key, then start a new webhook with it.
Turned off: its link was deleted
The one link this webhook watched is gone. Remove it, or start a new one for another link.

Troubleshooting

"Missing API key" or "Invalid, expired or revoked API key"
Check that the key starts with api_ and that the header reads Authorization: Bearer api_your_key. Keys for Zapier, n8n, MCP and Connect won't work here.
"Your plan doesn't include integrations."
Your plan doesn't include this feature. See plans.
"This API key is not allowed to..."
Keys can't be edited after they're created. Create a new one with that permission.
"Choose a domain. Your account has more than one."
Add domain_id to your request. GET /domains lists your choices.
"target_url must be a public https:// web address."
SCT Pro can't send to http://, private network or local addresses, or to ports other than the standard ones.
"Only standard links can be updated from an integration."
That link is a split test or rotator. Edit it in SCT Pro.
An event arrived twice
You may have started the same webhook twice, which shows as two rows on Integrations. Remove one with DELETE /webhooks/{id}.
The test event didn't arrive
Give it a few minutes, then check the webhook's status on Integrations. Make sure your tool is listening when you start the webhook.