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
- Open Integrations and scroll to the REST API box.
- Click Create REST API Key.
- 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.
- Set an expiration date if you want the key to stop working by itself. This is optional.
- 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."}}
| Status | Meaning |
|---|---|
200, 201 | It worked. 201 means something was created. |
401 | The key is missing, wrong, expired or revoked, or the account isn't active. |
403 | The plan doesn't include integrations, or the key doesn't have that permission. |
404 | That address doesn't exist, or the item isn't in this account. |
422 | The request couldn't be accepted. The message says why. This includes reaching your plan's link limit. |
429 | Too 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
429until the minute is up. - 100 webhooks and automations for each account. Zaps and n8n triggers count toward this too.
Links
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 parameter | What it does |
|---|---|
page | Page number. Starts at 1. |
per_page | Links on each page. Default 25, maximum 100. |
domain_id | Only links on this domain. |
path | Search: the exact path. |
name | Search: 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.
| Field | Required | What it does |
|---|---|---|
name | Yes | A label for you. |
url | Yes | Where the link sends visitors. |
path | No | The part after your domain. Leave it out and SCT Pro makes one. |
domain_id | Only with more than one domain | From GET /domains. |
group_id | No | From 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
| Field | Required | What it does |
|---|---|---|
event | Yes | One of the webhook events. |
target_url | Yes | Where 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_id | No | Watch one link. Leave it out to watch all your links. |
options.milestone_clicks | For click.milestone | The number of clicks to watch for. |
options.click_type | No | total (the default) or unique, for click.milestone. |
send_sample | No | Set 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_raceormanual),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
POSTwith a JSON body. Your address should answer with any2xxstatus. -
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
Authorizationwith the valueBearer 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 /webhooksonce with that address astarget_urlandsend_sampleset totrue, 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 setting | Use |
|---|---|
| Authentication | Bearer Token, using a REST API key from the Integrations page |
| App auth validator | GET https://app.simpleclicktracker.com/api/v1/rest/me, which answers 401 for a missing or bad key |
| Triggers | Webhooks Setup by API Request: POST /webhooks with the Pabbly address as target_url |
| Delete webhook | DELETE /webhooks/{id}, using the id from the subscribe response |
| Actions | POST /links, PATCH /links/{id}, GET /links, with a JSON body |
| Dropdowns | GET /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
2xxanswer. 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 readsAuthorization: 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_idto your request.GET /domainslists 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.