Introduction
Permbot REST surface for authentication, delegated client provisioning, tracked websites, and mock crawl ingestion.
This documentation aims to provide all the information you need to work with our API.
<aside>As you scroll, you'll see code examples for working with the API in different programming languages in the dark area to the right (or as part of the content on mobile).
You can switch the language used with the tabs at the top right (or from the nav menu at the top left on mobile).</aside>
Authenticating requests
To authenticate requests, include an Authorization header with the value "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}".
All authenticated endpoints are marked with a requires authentication badge in the documentation below.
Authenticate with Laravel Sanctum personal access tokens: call POST /api/login or POST /api/register, then paste the token into the Bearer field.
Account
Profile settings and two-factor authentication for the authenticated user.
Update display name
requires authentication
Example request:
curl --request PUT \
"https://dev.permbot.net/api/me/name" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"Acme Plumbing\"
}"
const url = new URL(
"https://dev.permbot.net/api/me/name"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Acme Plumbing"
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{"message":"...","user":{...}}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update password
requires authentication
Example request:
curl --request PUT \
"https://dev.permbot.net/api/me/password" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"current_password\": \"architecto\",
\"password\": \"|]|{+-\",
\"password_confirmation\": \"architecto\"
}"
const url = new URL(
"https://dev.permbot.net/api/me/password"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"current_password": "architecto",
"password": "|]|{+-",
"password_confirmation": "architecto"
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "..."
}
Example response (422, invalid password):
{
"message": "..."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update email
requires authentication
When the session was opened with two-factor authentication, the new email is applied immediately. Otherwise a confirmation link is sent to the current email address.
Example request:
curl --request PUT \
"https://dev.permbot.net/api/me/email" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"owner@newdomain.com\",
\"current_password\": \"architecto\"
}"
const url = new URL(
"https://dev.permbot.net/api/me/email"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "owner@newdomain.com",
"current_password": "architecto"
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, direct):
{"message":"...","pending_confirmation":false,"user":{...}}
Example response (200, pending):
{"message":"...","pending_confirmation":true,"user":{...}}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Cancel a pending email change
requires authentication
Example request:
curl --request DELETE \
"https://dev.permbot.net/api/me/email/pending" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/me/email/pending"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Two-factor authentication status
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/me/two-factor" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/me/two-factor"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Prepare two-factor setup
requires authentication
Returns a TOTP secret and otpauth URL for an authenticator app. Call enable with a valid code to finish.
Example request:
curl --request POST \
"https://dev.permbot.net/api/me/two-factor/prepare" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/me/two-factor/prepare"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Enable two-factor authentication
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/me/two-factor/enable" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"code\": \"123456\"
}"
const url = new URL(
"https://dev.permbot.net/api/me/two-factor/enable"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"code": "123456"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "...",
"recovery_codes": [
"XXXX-XXXX",
"..."
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Disable two-factor authentication
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/me/two-factor/disable" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"password\": \"|]|{+-\",
\"code\": \"architecto\"
}"
const url = new URL(
"https://dev.permbot.net/api/me/two-factor/disable"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"password": "|]|{+-",
"code": "architecto"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Activity logs
Append-only audit trail of panel actions with masked IP addresses and actor attribution. Agency accounts can list every event scoped to their reseller lineage; all users can list their own actions.
List activity logs for the authenticated user
requires authentication
Returns events where the authenticated user is the actor.
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/activity-logs?type=site_scan_completed&per_page=20" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/activity-logs"
);
const params = {
"type": "site_scan_completed",
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": [
{
"id": 1,
"type": "site_created",
"description": "Site plumbing.example was created.",
"target": "plumbing.example",
"variant": "neutral",
"actor": {
"id": 1,
"name": "Agency User",
"email": "agency@example.com"
},
"ip_address": "203.0.113.0",
"context": {
"site_id": 1,
"domain_name": "plumbing.example"
},
"created_at": "2026-05-19T12:00:00.000000Z"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List activity logs for the authenticated agency
requires authentication
Returns every event scoped to the agency account, including actions performed by child client users and background jobs tied to sites owned by the agency or its clients.
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/agency/activity-logs?type=site_created&per_page=20" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/agency/activity-logs"
);
const params = {
"type": "site_created",
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": [
{
"id": 1,
"type": "site_created",
"description": "Site plumbing.example was created.",
"target": "plumbing.example",
"variant": "neutral",
"actor": {
"id": 2,
"name": "Client User",
"email": "client@example.com"
},
"ip_address": "203.0.113.0",
"context": {
"site_id": 1,
"domain_name": "plumbing.example"
},
"created_at": "2026-05-19T12:00:00.000000Z"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Admin billing
PATCH api/admin/users/{userId}/subscription
requires authentication
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/admin/users/architecto/subscription" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"package_id\": 16,
\"starts_at\": \"2026-06-03T11:52:30\",
\"ends_at\": \"2052-06-26\"
}"
const url = new URL(
"https://dev.permbot.net/api/admin/users/architecto/subscription"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"package_id": 16,
"starts_at": "2026-06-03T11:52:30",
"ends_at": "2052-06-26"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Admin billing — invoices
GET api/admin/invoices
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/admin/invoices" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"status\": \"architecto\",
\"user_id\": 16,
\"per_page\": 22
}"
const url = new URL(
"https://dev.permbot.net/api/admin/invoices"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"status": "architecto",
"user_id": 16,
"per_page": 22
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/admin/invoices/{invoiceId}/approve
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/admin/invoices/architecto/approve" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/invoices/architecto/approve"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/admin/invoices/{invoiceId}/reject
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/admin/invoices/architecto/reject" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"payment_details\": \"b\"
}"
const url = new URL(
"https://dev.permbot.net/api/admin/invoices/architecto/reject"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"payment_details": "b"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Admin billing — packages
GET api/admin/packages/feature-options
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/admin/packages/feature-options" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/packages/feature-options"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/admin/packages
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/admin/packages" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/packages"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/admin/packages
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/admin/packages" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/packages"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
PATCH api/admin/packages/{packageId}
requires authentication
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/admin/packages/architecto" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/packages/architecto"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PATCH",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
DELETE api/admin/packages/{packageId}
requires authentication
Example request:
curl --request DELETE \
"https://dev.permbot.net/api/admin/packages/architecto" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/packages/architecto"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Admin support tickets
Admin group operators can manage all support requests.
GET api/admin/support/tickets
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/admin/support/tickets" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"per_page\": 1,
\"status\": \"closed\",
\"has_unread_requester_reply\": false
}"
const url = new URL(
"https://dev.permbot.net/api/admin/support/tickets"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"per_page": 1,
"status": "closed",
"has_unread_requester_reply": false
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/admin/support/tickets/{ticketUid}
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/admin/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/admin/support/tickets/{ticketUid}/messages
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/admin/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/messages" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"message\": \"b\"
}"
const url = new URL(
"https://dev.permbot.net/api/admin/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/messages"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"message": "b"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
PATCH api/admin/support/tickets/{ticketUid}
requires authentication
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/admin/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"status\": \"open\"
}"
const url = new URL(
"https://dev.permbot.net/api/admin/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"status": "open"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Admin users
Admin group operators can list and manage agency and client accounts. Provisioning is CLI-only.
List all agency and client accounts
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/admin/users?type=agency&name%5Blike%5D=Plumbing&email%5Beq%5D=owner%40example.com&email%5Blike%5D=%40example.com&suspended=&parent_id=1&sort=name&order=asc" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/users"
);
const params = {
"type": "agency",
"name[like]": "Plumbing",
"email[eq]": "owner@example.com",
"email[like]": "@example.com",
"suspended": "0",
"parent_id": "1",
"sort": "name",
"order": "asc",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": [
{
"id": 1,
"name": "Agency User",
"email": "agency@example.com",
"type": "agency",
"parent_id": null,
"suspended_at": null,
"sites_count": 2,
"agency_profile": {
"brand_name": "WhiteLabel Co",
"subdomain": "acme"
},
"parent": null,
"created_at": "2026-05-19T10:00:00.000000Z",
"updated_at": "2026-05-19T10:00:00.000000Z"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a single agency or client account summary
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/admin/users/12" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/users/12"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"id": 12,
"name": "Plumbing Co LLC",
"email": "owner@example.com",
"type": "client",
"parent_id": 1,
"suspended_at": null,
"sites_count": 2,
"agency_profile": null,
"parent": {
"id": 1,
"name": "Agency User",
"email": "agency@example.com",
"type": "agency"
},
"created_at": "2026-05-19T10:00:00.000000Z",
"updated_at": "2026-05-19T12:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update an agency or client account
requires authentication
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/admin/users/12" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"Plumbing Co LLC\",
\"email\": \"owner@example.com\",
\"password\": \"changeMe!234\",
\"password_confirmation\": \"architecto\",
\"brand_name\": \"WhiteLabel Co\",
\"subdomain\": \"acme\"
}"
const url = new URL(
"https://dev.permbot.net/api/admin/users/12"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Plumbing Co LLC",
"email": "owner@example.com",
"password": "changeMe!234",
"password_confirmation": "architecto",
"brand_name": "WhiteLabel Co",
"subdomain": "acme"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, success):
{
"user": {
"id": 12,
"name": "Plumbing Co LLC",
"email": "owner@example.com",
"type": "client",
"parent_id": 1,
"suspended_at": null,
"sites_count": 2,
"agency_profile": null,
"parent": {
"id": 1,
"name": "Agency User",
"email": "agency@example.com",
"type": "agency"
},
"created_at": "2026-05-19T10:00:00.000000Z",
"updated_at": "2026-05-19T12:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Suspend an agency or client account
requires authentication
Revokes all Sanctum tokens for the target user.
Example request:
curl --request POST \
"https://dev.permbot.net/api/admin/users/12/suspend" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/users/12/suspend"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, success):
{
"user": {
"id": 12,
"suspended_at": "2026-05-19T12:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Unsuspend an agency or client account
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/admin/users/12/unsuspend" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/users/12/unsuspend"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, success):
{
"user": {
"id": 12,
"suspended_at": null
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Agency clients
Agencies can create client child users scoped with parent_id.
List client child users for the authenticated agency
requires authentication
Filters and sort may be combined in a single request.
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/agency/clients?name%5Blike%5D=Plumbing&email%5Beq%5D=client-plumbing%40example.com&email%5Blike%5D=plumbing%40&sort=name&order=asc" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/agency/clients"
);
const params = {
"name[like]": "Plumbing",
"email[eq]": "client-plumbing@example.com",
"email[like]": "plumbing@",
"sort": "name",
"order": "asc",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": [
{
"id": 12,
"name": "Plumbing Co LLC",
"email": "client-plumbing@example.com",
"type": "client",
"parent_id": 1,
"sites_count": 2,
"created_at": "2026-05-19T10:00:00.000000Z",
"updated_at": "2026-05-19T10:00:00.000000Z"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create a client child user for the authenticated agency
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/agency/clients" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"Plumbing Co LLC\",
\"email\": \"client-plumbing@example.com\",
\"credential_mode\": \"manual\",
\"password\": \"changeMe!234\",
\"password_confirmation\": \"architecto\",
\"include_password_in_email\": false
}"
const url = new URL(
"https://dev.permbot.net/api/agency/clients"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Plumbing Co LLC",
"email": "client-plumbing@example.com",
"credential_mode": "manual",
"password": "changeMe!234",
"password_confirmation": "architecto",
"include_password_in_email": false
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, success):
{
"client": {
"id": 12,
"name": "Plumbing Co LLC",
"email": "client-plumbing@example.com",
"type": "client",
"parent_id": 1,
"sites_count": 0,
"created_at": "2026-05-19T10:00:00.000000Z",
"updated_at": "2026-05-19T10:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update a managed client child user
requires authentication
Send only keys you want to change.
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/agency/clients/12" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"Plumbing Co LLC\",
\"email\": \"client-plumbing@example.com\",
\"password\": \"changeMe!234\",
\"password_confirmation\": \"architecto\"
}"
const url = new URL(
"https://dev.permbot.net/api/agency/clients/12"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "Plumbing Co LLC",
"email": "client-plumbing@example.com",
"password": "changeMe!234",
"password_confirmation": "architecto"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, success):
{
"client": {
"id": 12,
"name": "Plumbing Co LLC",
"email": "client-plumbing@example.com",
"type": "client",
"parent_id": 1,
"sites_count": 2,
"created_at": "2026-05-19T10:00:00.000000Z",
"updated_at": "2026-05-19T12:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete a managed client child user
requires authentication
Clients that still own one or more sites cannot be deleted until those sites are removed or reassigned.
Example request:
curl --request DELETE \
"https://dev.permbot.net/api/agency/clients/12" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/agency/clients/12"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (204, success):
Empty response
Example response (409, has sites):
{
"message": "This client still owns one or more sites. Remove or reassign those sites before deleting the client."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Authentication
Tokens are issued via Laravel Sanctum personal access tokens.
Register
Creates agency (always seeds an AgencyProfile row you can customise later) or
a standalone client account with parent_id = null.
Standalone accounts can authenticate and manage POST /api/sites like agencies, unless a route intentionally
restricts access to reseller personas.
Legacy callers may omit account_type entirely; absent values default server-side to agency.
Example request:
curl --request POST \
"https://dev.permbot.net/api/register" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"account_type\": \"client\",
\"name\": \"Acme Plumbing\",
\"email\": \"owner@example.com\",
\"password\": \"changeMe!234\",
\"brand_name\": \"WhiteLabel Co.\",
\"subdomain\": \"acme\",
\"locale\": \"tr\",
\"password_confirmation\": \"architecto\"
}"
const url = new URL(
"https://dev.permbot.net/api/register"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"account_type": "client",
"name": "Acme Plumbing",
"email": "owner@example.com",
"password": "changeMe!234",
"brand_name": "WhiteLabel Co.",
"subdomain": "acme",
"locale": "tr",
"password_confirmation": "architecto"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, success):
{
"token": "1|plainTextToken",
"token_type": "Bearer",
"user": {
"id": 1,
"name": "Acme Plumbing",
"email": "owner@example.com",
"type": "agency"
}
}
Example response (422, validation):
{
"message": "...",
"errors": {}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Login
Validates credentials and returns a Bearer token. The type reflects the authenticated user (admin,
admin_group, agency, or client).
Example request:
curl --request POST \
"https://dev.permbot.net/api/login" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"agency@example.com\",
\"password\": \"changeMe!234\"
}"
const url = new URL(
"https://dev.permbot.net/api/login"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "agency@example.com",
"password": "changeMe!234"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, success):
{
"token": "1|plainTextToken",
"token_type": "Bearer",
"user": {
"id": 1,
"name": "Agency User",
"email": "agency@example.com",
"type": "agency"
}
}
Example response (401, invalid credentials):
{
"message": "..."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Complete login with two-factor authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/login/two-factor" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"two_factor_token\": \"architecto\",
\"code\": \"123456\",
\"recovery_code\": \"architecto\"
}"
const url = new URL(
"https://dev.permbot.net/api/login/two-factor"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"two_factor_token": "architecto",
"code": "123456",
"recovery_code": "architecto"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, success):
{"token":"1|plainTextToken","token_type":"Bearer","user":{...}}
Example response (422, invalid code):
{
"message": "..."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Forgot password
Sends a password reset link when an active account exists for the given email. The response is always the same to avoid email enumeration.
Example request:
curl --request POST \
"https://dev.permbot.net/api/forgot-password" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"agency@example.com\"
}"
const url = new URL(
"https://dev.permbot.net/api/forgot-password"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "agency@example.com"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "..."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Reset password
Completes a password reset using the token from the email link. All existing API tokens for the user are revoked.
Example request:
curl --request POST \
"https://dev.permbot.net/api/reset-password" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"agency@example.com\",
\"token\": \"abc123...\",
\"password\": \"changeMe!234\",
\"password_confirmation\": \"architecto\"
}"
const url = new URL(
"https://dev.permbot.net/api/reset-password"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "agency@example.com",
"token": "abc123...",
"password": "changeMe!234",
"password_confirmation": "architecto"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "..."
}
Example response (422, invalid token):
{
"message": "..."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Confirm pending email change
Example request:
curl --request POST \
"https://dev.permbot.net/api/confirm-email-change" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"email\": \"owner@example.com\",
\"token\": \"architecto\"
}"
const url = new URL(
"https://dev.permbot.net/api/confirm-email-change"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"email": "owner@example.com",
"token": "architecto"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{
"message": "..."
}
Example response (422, invalid token):
{
"message": "..."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Logout
requires authentication
Revokes the Sanctum personal access token used on this request so it cannot be reused. Other sessions (tokens issued on other devices or earlier logins) stay valid unless revoked separately.
Example request:
curl --request POST \
"https://dev.permbot.net/api/logout" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/logout"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200):
{
"message": "..."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Current authenticated user (refresh session after role changes).
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/me" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/me"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update panel locale
requires authentication
Persists the user's preferred panel language for API copy and transactional emails.
Example request:
curl --request PUT \
"https://dev.permbot.net/api/me/locale" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"locale\": \"tr\"
}"
const url = new URL(
"https://dev.permbot.net/api/me/locale"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"locale": "tr"
};
fetch(url, {
method: "PUT",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200):
{"message":"...","user":{"id":1,"locale":"tr",...}}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Billing
GET api/billing/status
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/billing/status" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/status"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/billing/packages
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/billing/packages" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/packages"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/billing/payment-methods
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/billing/payment-methods" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/payment-methods"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/billing/subscription
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/billing/subscription" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/subscription"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/billing/invoices
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/billing/invoices" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/invoices"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/billing/billing-profile
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/billing/billing-profile" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/billing-profile"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
PUT api/billing/billing-profile
requires authentication
Example request:
curl --request PUT \
"https://dev.permbot.net/api/billing/billing-profile" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/billing-profile"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PUT",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/billing/upgrade
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/billing/upgrade" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"package_id\": 16,
\"payment_method\": \"architecto\",
\"payment_details\": \"n\"
}"
const url = new URL(
"https://dev.permbot.net/api/billing/upgrade"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"package_id": 16,
"payment_method": "architecto",
"payment_details": "n"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/billing/upgrade/cancel
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/billing/upgrade/cancel" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/upgrade/cancel"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Billing — iyzico
GET api/billing/iyzico/config
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/billing/iyzico/config" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/iyzico/config"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/billing/invoices/{invoiceId}/iyzico/checkout
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/billing/invoices/architecto/iyzico/checkout" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/invoices/architecto/iyzico/checkout"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/billing/iyzico/complete
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/billing/iyzico/complete" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"token\": \"b\"
}"
const url = new URL(
"https://dev.permbot.net/api/billing/iyzico/complete"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"token": "b"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Blog (public)
Marketing site blog content. No authentication required; only published posts are exposed.
GET api/blog/categories
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/blog/categories" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/categories"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (422):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 120
x-ratelimit-remaining: 115
access-control-allow-origin: *
{
"message": "A content locale is required (e.g. tr or en).",
"errors": {
"locale": [
"A content locale is required (e.g. tr or en)."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/blog/tags
requires authentication
GET api/blog/posts
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/blog/posts" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/posts"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (422):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 120
x-ratelimit-remaining: 113
access-control-allow-origin: *
{
"message": "The Locale field is required.",
"errors": {
"locale": [
"The Locale field is required."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/blog/posts/{slug}
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/blog/posts/0cl" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/posts/0cl"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (422):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 120
x-ratelimit-remaining: 112
access-control-allow-origin: *
{
"message": "A content locale is required (e.g. tr or en).",
"errors": {
"locale": [
"A content locale is required (e.g. tr or en)."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Blog management
GET api/blog/manage/categories
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/blog/manage/categories" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/manage/categories"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/blog/manage/categories
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/blog/manage/categories" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"b\",
\"slug\": \"n\"
}"
const url = new URL(
"https://dev.permbot.net/api/blog/manage/categories"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "b",
"slug": "n"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
PATCH api/blog/manage/categories/{categoryId}
requires authentication
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/blog/manage/categories/architecto" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"name\": \"b\",
\"slug\": \"n\"
}"
const url = new URL(
"https://dev.permbot.net/api/blog/manage/categories/architecto"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"name": "b",
"slug": "n"
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
DELETE api/blog/manage/categories/{categoryId}
requires authentication
Example request:
curl --request DELETE \
"https://dev.permbot.net/api/blog/manage/categories/architecto" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/manage/categories/architecto"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/blog/manage/tags
requires authentication
POST api/blog/manage/tags
requires authentication
GET api/blog/manage/posts
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/blog/manage/posts" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/manage/posts"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/blog/manage/posts
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/blog/manage/posts" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/manage/posts"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/blog/manage/posts/{postId}
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/blog/manage/posts/564" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/manage/posts/564"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
PATCH api/blog/manage/posts/{postId}
requires authentication
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/blog/manage/posts/564" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/manage/posts/564"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PATCH",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
DELETE api/blog/manage/posts/{postId}
requires authentication
Example request:
curl --request DELETE \
"https://dev.permbot.net/api/blog/manage/posts/564" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/blog/manage/posts/564"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/blog/manage/media
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/blog/manage/media" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: multipart/form-data" \
--header "Accept: application/json" \
--form "file=@/private/var/folders/gb/r30mg0d93vq6d6mm0zjg9q8r0000gp/T/php0jmte8d77ru7dGQKfvw" const url = new URL(
"https://dev.permbot.net/api/blog/manage/media"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "multipart/form-data",
"Accept": "application/json",
};
const body = new FormData();
body.append('file', document.querySelector('input[name="file"]').files[0]);
fetch(url, {
method: "POST",
headers,
body,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Consent records
Browse append-only visitor consent logs for sites in scope and generate evidence documents (for example when presenting records for a data-subject request). List views show truncated IP addresses; document export includes the stored anonymized IP used for matching.
List consent records
requires authentication
Returns individual consent log rows (not aggregated analytics). IP addresses are truncated
in the list; use an exact visitor IP in ip_address to search (matched after the same
anonymization applied at ingestion).
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/consent-records?site_id=3&client_id=12&consent_uid=550e8400-e29b-41d4-a716-446655440000&ip_address=198.51.100.42&from=2026-05-01&to=2026-05-31&sort=id&order=desc&per_page=20" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/consent-records"
);
const params = {
"site_id": "3",
"client_id": "12",
"consent_uid": "550e8400-e29b-41d4-a716-446655440000",
"ip_address": "198.51.100.42",
"from": "2026-05-01",
"to": "2026-05-31",
"sort": "id",
"order": "desc",
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": [
{
"id": 1,
"site_id": 3,
"site_domain": "example.com",
"site_company": "Example Ltd",
"consent_uid": "550e8400-e29b-41d4-a716-446655440000",
"preference": "accepted_all",
"accepted_categories": {
"essential": true,
"analytics": true,
"marketing": true
},
"policy_version": 1,
"ip_address": "198.51.xxx.xxx",
"integrity_hash": "abc",
"created_at": "2026-05-19T12:00:00.000000Z",
"updated_at": "2026-05-19T12:00:00.000000Z"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1,
"filters": {
"site_id": null,
"client_id": null
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Generate a consent evidence document
requires authentication
Builds a structured JSON document of all matching consent rows for legal presentation.
Requires ip_address; optionally narrow with consent_uid, date range, and site scope.
Stored anonymized IPs are included in full (as persisted at ingestion).
Example request:
curl --request POST \
"https://dev.permbot.net/api/consent-records/document" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"ip_address\": \"198.51.100.42\",
\"consent_uid\": \"550e8400-e29b-41d4-a716-446655440000\",
\"site_id\": 3,
\"client_id\": 12,
\"from\": \"2026-05-01\",
\"to\": \"2026-05-31\"
}"
const url = new URL(
"https://dev.permbot.net/api/consent-records/document"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"ip_address": "198.51.100.42",
"consent_uid": "550e8400-e29b-41d4-a716-446655440000",
"site_id": 3,
"client_id": 12,
"from": "2026-05-01",
"to": "2026-05-31"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, success):
{
"data": {
"generated_at": "2026-05-19T12:00:00.000000Z",
"generated_by": {
"id": 1,
"name": "Agency User",
"email": "agency@example.com",
"type": "agency"
},
"criteria": {
"site_id": null,
"client_id": null,
"ip_address_masked": "198.51.100.0",
"consent_uid": null,
"from": null,
"to": null
},
"record_count": 1,
"records": [],
"disclaimer": "..."
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Cookie dictionary
Read-only reference catalogue of known cookie names and patterns used during scans and widget copy.
List cookie dictionary entries
requires authentication
Filters, free-text search, and sort may be combined in a single request.
Show a cookie dictionary entry
requires authentication
Dashboard statistics
Aggregated metrics for agency and client dashboards. All endpoints resolve a date window automatically: invalid or missing date inputs fall back to the current month (overview, site statuses) or current year (consent preferences).
Dashboard overview KPIs
requires authentication
Site status counts reflect the current fleet snapshot within the optional site/client scope.
Period-bound metrics (sites_created, failed_scan_runs, consent_events) use the resolved date window.
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/stats/overview?year=2026&month=5&from=2026-05-01&to=2026-05-31&site_id=3&client_id=12" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/stats/overview"
);
const params = {
"year": "2026",
"month": "5",
"from": "2026-05-01",
"to": "2026-05-31",
"site_id": "3",
"client_id": "12",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"meta": {
"period": {
"from": "2026-05-01",
"to": "2026-05-31",
"granularity": "month"
},
"comparison_period": {
"from": "2026-04-01",
"to": "2026-04-30"
},
"filters": {
"site_id": null,
"client_id": null
}
},
"data": {
"total_sites": 24,
"active_sites": 18,
"pending_sites": 3,
"queued_sites": 1,
"scanning_sites": 1,
"failed_sites": 1,
"in_progress_sites": 2,
"sites_created": 2,
"sites_created_change": 2,
"failed_scan_runs": 1,
"consent_events": 450,
"average_consent_rate": 84.3,
"managed_clients": 8
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Site status distribution
requires authentication
Returns the current status breakdown for all sites in scope. The resolved period is included in meta
for UI date pickers; status counts are a live snapshot (not filtered by site creation date).
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/stats/site-statuses?year=2026&month=5&from=2026-05-01&to=2026-05-31&site_id=3&client_id=12" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/stats/site-statuses"
);
const params = {
"year": "2026",
"month": "5",
"from": "2026-05-01",
"to": "2026-05-31",
"site_id": "3",
"client_id": "12",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"meta": {
"period": {
"from": "2026-05-01",
"to": "2026-05-31",
"granularity": "month"
},
"filters": {
"site_id": null,
"client_id": null
}
},
"data": {
"total": 24,
"in_progress": 2,
"by_status": {
"pending": 3,
"queued": 1,
"scanning": 1,
"active": 18,
"failed": 1
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Monthly cookie consent preference distribution
requires authentication
Each consent log row is classified as accepted_all, partially_accepted, or rejected
from normalized accepted_categories. Defaults to the current calendar year when no valid date input is sent.
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/stats/consent-preferences?year=2026&month=5&from=2026-01-01&to=2026-12-31&site_id=3&client_id=12" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/stats/consent-preferences"
);
const params = {
"year": "2026",
"month": "5",
"from": "2026-01-01",
"to": "2026-12-31",
"site_id": "3",
"client_id": "12",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"meta": {
"period": {
"from": "2026-01-01",
"to": "2026-12-31",
"granularity": "year"
},
"filters": {
"site_id": null,
"client_id": null
}
},
"data": {
"months": [
{
"month": "2026-01",
"accepted_all": 1200,
"partially_accepted": 200,
"rejected": 300,
"total": 1700
}
],
"totals": {
"accepted_all": 1200,
"partially_accepted": 200,
"rejected": 300,
"total": 1700
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Endpoints
Authenticate the request for channel access.
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/broadcasting/auth" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/broadcasting/auth"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/system/status
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/system/status" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/system/status"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"data": {
"status": "operational",
"database_connected": true,
"database": "permbot",
"redis_connected": true,
"queue_connected": true,
"tables": {
"notifications": true,
"activity_logs": true,
"site_verification_runs": true,
"cookie_consents": true,
"sites": true
},
"consent_databases": {
"consent_tr": {
"connected": true,
"database": "permbot_consent_tr",
"cookie_consents": true
}
},
"checked_at": "2026-06-03T11:52:29+00:00"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Serves hardened vanilla JS bundles keyed by **`sites.script_id`** (UUID).
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/v1/widget/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc.js" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/v1/widget/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc.js"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (404):
Show headers
content-type: application/javascript; charset=UTF-8
x-robots-tag: noindex
cache-control: no-cache, private
x-ratelimit-limit: 240
x-ratelimit-remaining: 239
// Permbot: unknown bundle identifier
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Returns the latest append-only consent log row for a visitor on a mapped site bundle (script_id UUID).
requires authentication
404: No row for this consent_uid on this site — embedded widgets clear matching localStorage and show the CMP again.
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/v1/widget/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/latest-consent" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"consent_uid\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\"
}"
const url = new URL(
"https://dev.permbot.net/api/v1/widget/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/latest-consent"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"consent_uid": "6ff8f7f6-1eb3-3525-be4a-3932c805afed"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (404):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 240
x-ratelimit-remaining: 238
{
"message": "Consent record could not be found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Visitor-facing catalogue of declared storage signals grouped by CMP category (localized descriptions).
requires authentication
POST api/v1/consents
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/v1/consents" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"site_id\": 16,
\"consent_uid\": \"a4855dc5-0acb-33c3-b921-f4291f719ca0\",
\"accepted_categories\": {
\"analytics\": false,
\"marketing\": true
}
}"
const url = new URL(
"https://dev.permbot.net/api/v1/consents"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"site_id": 16,
"consent_uid": "a4855dc5-0acb-33c3-b921-f4291f719ca0",
"accepted_categories": {
"analytics": false,
"marketing": true
}
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/billing/iyzico/callback
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/billing/iyzico/callback" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/billing/iyzico/callback"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (302):
Show headers
cache-control: no-cache, private
location: https://ui.permbot.net/dashboard/billing/payment-result?status=error&reason=missing_token
content-type: text/html; charset=utf-8
access-control-allow-origin: *
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="refresh" content="0;url='https://ui.permbot.net/dashboard/billing/payment-result?status=error&reason=missing_token'" />
<title>Redirecting to https://ui.permbot.net/dashboard/billing/payment-result?status=error&reason=missing_token</title>
</head>
<body>
Redirecting to <a href="https://ui.permbot.net/dashboard/billing/payment-result?status=error&reason=missing_token">https://ui.permbot.net/dashboard/billing/payment-result?status=error&reason=missing_token</a>.
</body>
</html>
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/realtime/config
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/realtime/config" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/realtime/config"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/realtime/live-activity
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/realtime/live-activity" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"limit\": 16
}"
const url = new URL(
"https://dev.permbot.net/api/realtime/live-activity"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"limit": 16
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/data-locations
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/data-locations" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/data-locations"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Start an ephemeral multi-page cookie probe for onboarding / demo flows.
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/v1/public/quick-scans" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"domain\": \"b\",
\"max_pages\": 2,
\"basic_auth\": {
\"username\": \"g\",
\"password\": \"{+-0pBNvYgx\"
}
}"
const url = new URL(
"https://dev.permbot.net/api/v1/public/quick-scans"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"domain": "b",
"max_pages": 2,
"basic_auth": {
"username": "g",
"password": "{+-0pBNvYgx"
}
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Poll scan status and, when finished, cookie harvest details.
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 30
x-ratelimit-remaining: 20
{
"message": "Invalid or expired request signature."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/public/quick-scans/{scanId}/widget
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/widget" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/widget"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 30
x-ratelimit-remaining: 19
{
"message": "Invalid or expired request signature."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
PATCH api/v1/public/quick-scans/{scanId}/widget
requires authentication
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/widget" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/widget"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "PATCH",
headers,
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/public/quick-scans/{scanId}/preview
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/preview" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/preview"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 30
x-ratelimit-remaining: 18
{
"message": "Invalid or expired request signature."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/public/quick-scans/{scanId}/cookies
requires authentication
GET api/v1/public/quick-scans/{scanId}/widget.js
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/widget.js" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/widget.js"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (404):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 120
x-ratelimit-remaining: 106
{
"message": "Quick scan session could not be found or has expired."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/public/quick-scans/{scanId}/latest-consent
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/latest-consent" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"consent_uid\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\"
}"
const url = new URL(
"https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/latest-consent"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"consent_uid": "6ff8f7f6-1eb3-3525-be4a-3932c805afed"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (404):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 120
x-ratelimit-remaining: 105
{
"message": "Consent record could not be found."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/public/quick-scans/{scanId}/consents
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/consents" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"consent_uid\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\",
\"accepted_categories\": {
\"analytics\": true,
\"marketing\": true
},
\"policy_version\": 16
}"
const url = new URL(
"https://dev.permbot.net/api/v1/public/quick-scans/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/consents"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"consent_uid": "6ff8f7f6-1eb3-3525-be4a-3932c805afed",
"accepted_categories": {
"analytics": true,
"marketing": true
},
"policy_version": 16
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Integrity timestamps
Daily TÜBİTAK-stamped integrity hash chain batches for the authenticated billing account.
List integrity timestamp batches
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/integrity-timestamps?from=2026-05-01&to=2026-05-31&consent_location=tr&status=completed&per_page=20" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/integrity-timestamps"
);
const params = {
"from": "2026-05-01",
"to": "2026-05-31",
"consent_location": "tr",
"status": "completed",
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show integrity timestamp batch detail
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/integrity-timestamps/architecto" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/integrity-timestamps/architecto"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Download integrity timestamp report archive (ZIP)
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/integrity-timestamps/architecto/download" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/integrity-timestamps/architecto/download"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Notifications
In-app notifications for authenticated users (database channel). Site-related events are delivered to the site owner and, when the owner is an agency child client, to the managing agency as well.
List notifications for the authenticated user
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/admin/notifications?unread_only=1&per_page=20" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"unread_only\": false,
\"per_page\": 1
}"
const url = new URL(
"https://dev.permbot.net/api/admin/notifications"
);
const params = {
"unread_only": "1",
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"unread_only": false,
"per_page": 1
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, success):
{
"data": [
{
"id": "9b2c4f0e-8a1d-4b3c-9d0e-1f2a3b4c5d6e",
"type": "site_created",
"title": "Site added",
"body": "Plumbing Co LLC (plumbing.example) was added.",
"context": {
"site_id": 1
},
"read_at": null,
"created_at": "2026-05-19T12:00:00.000000Z"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Unread notification count
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/admin/notifications/unread-count" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/notifications/unread-count"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"unread_count": 3
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Mark all notifications as read
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/admin/notifications/read-all" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/notifications/read-all"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"marked_read": 3
},
"message": "All notifications marked as read."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Mark a single notification as read
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/admin/notifications/9b2c4f0e-8a1d-4b3c-9d0e-1f2a3b4c5d6e/read" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/admin/notifications/9b2c4f0e-8a1d-4b3c-9d0e-1f2a3b4c5d6e/read"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"id": "9b2c4f0e-8a1d-4b3c-9d0e-1f2a3b4c5d6e",
"type": "site_created",
"title": "Site added",
"body": "Plumbing Co LLC (plumbing.example) was added.",
"context": {
"site_id": 1
},
"read_at": "2026-05-19T12:05:00.000000Z",
"created_at": "2026-05-19T12:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List notifications for the authenticated user
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/notifications?unread_only=1&per_page=20" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"unread_only\": false,
\"per_page\": 1
}"
const url = new URL(
"https://dev.permbot.net/api/notifications"
);
const params = {
"unread_only": "1",
"per_page": "20",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"unread_only": false,
"per_page": 1
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, success):
{
"data": [
{
"id": "9b2c4f0e-8a1d-4b3c-9d0e-1f2a3b4c5d6e",
"type": "site_created",
"title": "Site added",
"body": "Plumbing Co LLC (plumbing.example) was added.",
"context": {
"site_id": 1
},
"read_at": null,
"created_at": "2026-05-19T12:00:00.000000Z"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Unread notification count
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/notifications/unread-count" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/notifications/unread-count"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"unread_count": 3
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Mark all notifications as read
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/notifications/read-all" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/notifications/read-all"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"marked_read": 3
},
"message": "All notifications marked as read."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Mark a single notification as read
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/notifications/9b2c4f0e-8a1d-4b3c-9d0e-1f2a3b4c5d6e/read" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/notifications/9b2c4f0e-8a1d-4b3c-9d0e-1f2a3b4c5d6e/read"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "POST",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"id": "9b2c4f0e-8a1d-4b3c-9d0e-1f2a3b4c5d6e",
"type": "site_created",
"title": "Site added",
"body": "Plumbing Co LLC (plumbing.example) was added.",
"context": {
"site_id": 1
},
"read_at": "2026-05-19T12:05:00.000000Z",
"created_at": "2026-05-19T12:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Public pricing
Marketing site pricing tables. No authentication required.
GET api/public/packages
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/public/packages" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"audience\": \"architecto\"
}"
const url = new URL(
"https://dev.permbot.net/api/public/packages"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"audience": "architecto"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (422):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 120
x-ratelimit-remaining: 116
access-control-allow-origin: *
{
"message": "The selected audience is invalid.",
"errors": {
"audience": [
"The selected audience is invalid."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Sites
Sites belong to exactly one users record (sites.user_id). Agencies may optionally associate a newly created
site with one of their child clients (client_id), effectively storing the client as the owning user row.
Cookie discovery runs only after POST /api/sites/{siteId}/cookie-scan dispatches DiscoverAndSaveCookiesJob to the queue (pending, queued, scanning, active, failed).
List sites visible to the authenticated user
requires authentication
- agency: Sites owned by the agency user or any of its child clients (
parent_idlineage). - client: Sites where
sites.user_idmatches the authenticated client.
Filters and sort may be combined in a single request.
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/sites?status%5Beq%5D=active&status%5Bneq%5D=failed&user_id=12&owner_id=12&sort=company_name&order=asc" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/sites"
);
const params = {
"status[eq]": "active",
"status[neq]": "failed",
"user_id": "12",
"owner_id": "12",
"sort": "company_name",
"order": "asc",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": [
{
"id": 1,
"user_id": 2,
"company_name": "Plumbing Co LLC",
"domain_name": "plumbing.example",
"script_id": "9b7c4f2e-8a1d-4b3c-9d0e-1f2a3b4c5d6e",
"status": "active",
"settings": null,
"last_scan_requested_at": "2026-05-19T11:00:00.000000Z",
"last_scan_started_at": "2026-05-19T11:00:05.000000Z",
"last_scan_finished_at": "2026-05-19T11:02:00.000000Z",
"last_scan_error": null,
"current_policy_version": 1,
"created_at": "2026-05-19T10:00:00.000000Z",
"updated_at": "2026-05-19T11:02:00.000000Z",
"owner": {
"id": 2,
"name": "Client User",
"email": "client@example.com",
"type": "client",
"parent_id": 1
}
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Create a site
requires authentication
Sets status to pending. Cookie scanning does not start automatically — call POST /api/sites/{siteId}/cookie-scan to enqueue DiscoverAndSaveCookiesJob.
Site verification (reachability + widget script) is queued automatically and does not affect sites.status.
Example request:
curl --request POST \
"https://dev.permbot.net/api/sites" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"company_name\": \"Plumbing Co LLC\",
\"domain_name\": \"plumbing.example\",
\"settings\": {
\"theme\": \"dark\"
},
\"client_id\": 12,
\"consent_location\": \"architecto\",
\"disabled_pages\": [
\"n\"
],
\"share_consent_across_subdomains\": true
}"
const url = new URL(
"https://dev.permbot.net/api/sites"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"company_name": "Plumbing Co LLC",
"domain_name": "plumbing.example",
"settings": {
"theme": "dark"
},
"client_id": 12,
"consent_location": "architecto",
"disabled_pages": [
"n"
],
"share_consent_across_subdomains": true
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (201, success):
{
"data": {
"id": 1,
"user_id": 1,
"company_name": "Plumbing Co LLC",
"domain_name": "plumbing.example",
"script_id": "9b7c4f2e-8a1d-4b3c-9d0e-1f2a3b4c5d6e",
"status": "pending",
"settings": null,
"last_scan_requested_at": null,
"last_scan_started_at": null,
"last_scan_finished_at": null,
"last_scan_error": null,
"current_policy_version": 0,
"created_at": "2026-05-19T12:00:00.000000Z",
"updated_at": "2026-05-19T12:00:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update site fields visible to the authenticated owner (or an agency managing the client owner).
requires authentication
Send only keys you want to change. When settings is present, it is deep-merged into existing sites.settings
(array_replace_recursive), so nested objects such as widget.theme are preserved unless overridden by the patch.
Set settings to null to clear all stored settings for the site.
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/sites/1" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"company_name\": \"Plumbing Co LLC\",
\"domain_name\": \"plumbing.example\",
\"settings\": {
\"widget\": {
\"banner\": {
\"show_reject_optional\": false
}
}
},
\"consent_location\": \"architecto\",
\"disabled_pages\": [
\"n\"
],
\"share_consent_across_subdomains\": false
}"
const url = new URL(
"https://dev.permbot.net/api/sites/1"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"company_name": "Plumbing Co LLC",
"domain_name": "plumbing.example",
"settings": {
"widget": {
"banner": {
"show_reject_optional": false
}
}
},
"consent_location": "architecto",
"disabled_pages": [
"n"
],
"share_consent_across_subdomains": false
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, success):
{
"data": {
"id": 1,
"user_id": 1,
"company_name": "Plumbing Co LLC",
"domain_name": "plumbing.example",
"script_id": "9b7c4f2e-8a1d-4b3c-9d0e-1f2a3b4c5d6e",
"status": "pending",
"settings": {
"widget": {
"banner": {
"show_reject_optional": false
}
}
},
"last_scan_requested_at": null,
"last_scan_started_at": null,
"last_scan_finished_at": null,
"last_scan_error": null,
"current_policy_version": 0,
"created_at": "2026-05-19T12:00:00.000000Z",
"updated_at": "2026-05-19T12:10:00.000000Z"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Delete a site
requires authentication
When the site has no visitor consent rows, the site row and related central data (signals, scan runs, verification runs) are removed permanently.
When consent history exists, the site is archived (deleted_at set): it no longer appears for the owner, does not count toward subscription site limits, and the public widget stops serving for its script_id.
Admins and super-admins can still list and open archived sites (is_deleted = true).
Example request:
curl --request DELETE \
"https://dev.permbot.net/api/sites/1" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/sites/1"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (200, purged):
{
"data": {
"site_id": 1,
"deletion": "purged"
}
}
Example response (200, archived):
{
"data": {
"site_id": 1,
"deletion": "archived"
}
}
Example response (409, already deleted):
{
"message": "This site has already been removed."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Site detail (**summary** + counters, recent signals, last scan runs)
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/sites/1" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/sites/1"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"site": {
"id": 1,
"user_id": 2,
"company_name": "Plumbing Co LLC",
"domain_name": "plumbing.example",
"script_id": "9b7c4f2e-8a1d-4b3c-9d0e-1f2a3b4c5d6e",
"status": "active",
"settings": null,
"last_scan_requested_at": "2026-05-19T11:00:00.000000Z",
"last_scan_started_at": "2026-05-19T11:00:05.000000Z",
"last_scan_finished_at": "2026-05-19T11:02:00.000000Z",
"last_scan_error": null,
"created_at": "2026-05-19T10:00:00.000000Z",
"updated_at": "2026-05-19T11:02:00.000000Z",
"signals_count": 1
},
"owner": {
"id": 2,
"name": "Client User",
"email": "client@example.com",
"type": "client",
"parent_id": 1
},
"signal_summary": {
"by_type": {
"cookie": 1
},
"by_category": {
"analytics": 1
},
"by_discovery_source": {
"scanner": 1
}
},
"recent_signals": [
{
"id": 1,
"type": "cookie",
"discovery_source": "scanner",
"name": "_ga",
"category": "analytics",
"cookie_domain": ".plumbing.example",
"expires_at": null,
"visible_to_users": true,
"updated_at": "2026-05-19T11:02:00.000000Z",
"created_at": "2026-05-19T11:02:00.000000Z"
}
],
"recent_scan_runs": [
{
"id": 1,
"status": "completed",
"started_at": "2026-05-19T11:00:05.000000Z",
"finished_at": "2026-05-19T11:02:00.000000Z",
"pages_visited": 3,
"scanner_cookie_rows": 1,
"local_storage_rows": 0,
"session_storage_rows": 0,
"indexed_db_rows": 0,
"total_signals_written": 1,
"targets_snapshot": [
"https://plumbing.example/"
],
"error_summary": null,
"created_at": "2026-05-19T11:00:05.000000Z"
}
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Enqueue hybrid cookie crawl for the site (queue-backed)
requires authentication
Queues DiscoverAndSaveCookiesJob and sets status to queued while the worker has not begun yet.
Returns 409 while scanning; 422 while already queued.
GET api/sites/{siteId}/cookie-scan
requires authentication
Add a manual site signal row (**`discovery_source`** = **`manual`**; never replaced by crawler).
requires authentication
Update editable fields: **`category`**, **`description_*`**, and **`visible_to_users`**.
requires authentication
visible_to_users controls whether this signal participates in end-user cookie-consent UX and downstream consent/logging flows. When false, scanners still persist scanner rows, but integrations may omit the row from banners and exported consent records.
Delete a **`manual`** signal row.
requires authentication
Scanner-derived rows cannot be deleted; PATCH with visible_to_users = false removes them from end-user-facing consent workflows instead.
Site verification
Informational checks (site reachability + widget script presence). Does not change sites.status or block usage.
Separate from cookie discovery (POST /api/sites/{siteId}/cookie-scan).
Queue a new verification run (async)
requires authentication
Returns 202 when queued. Poll with GET /api/sites/{siteId}/verification.
Returns 409 while a run is running; 422 while queued (worker not started yet).
Example request:
curl --request POST \
"https://dev.permbot.net/api/sites/1/verification" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"basic_auth\": {
\"username\": \"staging\",
\"password\": \"secret\"
}
}"
const url = new URL(
"https://dev.permbot.net/api/sites/1/verification"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"basic_auth": {
"username": "staging",
"password": "secret"
}
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Latest verification run for polling.
requires authentication
When no run exists yet (e.g. legacy sites created before verification shipped), the first GET automatically queues an initial run so polling alone is enough for the UI.
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/sites/1/verification" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/sites/1/verification"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Site widget settings
Dedicated widget configuration for a site: stored overrides, effective merged settings, resolved preview payload,
customizable field schema, starter template, and embed URLs. Updates deep-merge into sites.settings.widget only.
Widget configuration bundle for panel editing and live preview
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/sites/1/widget?preview_locale=tr" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/sites/1/widget"
);
const params = {
"preview_locale": "tr",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"site_id": 1,
"script_id": "9b7c4f2e-8a1d-4b3c-9d0e-1f2a3b4c5d6e",
"settings": null,
"effective": {
"theme": {
"appearance": "light"
}
},
"resolved": {
"locale": "en",
"banner_title": "Cookie preferences"
},
"schema": {
"locales": [
"en",
"tr"
],
"fields": []
},
"template": {
"copy": {
"en": {
"title": "Cookie preferences"
}
}
},
"defaults": {
"theme": {
"appearance": "light"
}
},
"embed": {
"script_url": "https://example.com/api/v1/widget/9b7c4f2e.js",
"preview_url": null
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Update widget settings (partial deep merge)
requires authentication
Send only keys you want to change at the widget root (same shape as settings in the GET response).
The response includes schema, template, and resolved preview data again.
Example request:
curl --request PATCH \
"https://dev.permbot.net/api/sites/1/widget?preview_locale=tr" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"consent_location\": \"tr\",
\"locale\": \"sr_BA\",
\"copy\": {
\"en\": {
\"title\": \"Cookies\",
\"intro_html\": \"<p>We use cookies.<\\/p>\"
},
\"0\": {
\"title\": \"z\",
\"intro_html\": \"m\"
}
},
\"cookie_policy_url\": \"https:\\/\\/example.com\\/cookies\",
\"theme\": {
\"appearance\": \"dark\",
\"border_radius_px\": 22,
\"z_index\": 67,
\"colors\": {
\"primary\": \"z\",
\"primary_hover\": \"m\",
\"danger\": \"i\",
\"danger_hover\": \"y\",
\"surface\": \"v\",
\"text\": \"d\",
\"text_muted\": \"l\",
\"border\": \"j\",
\"switch_track_off\": \"n\",
\"switch_track_on\": \"i\",
\"shadow\": \"k\",
\"banner_max_width_px\": 14
}
},
\"banner\": {
\"show_reject_optional\": true
},
\"category_hints\": {
\"copy\": {
\"tr\": {
\"essential\": \"…\",
\"analytics\": \"…\",
\"marketing\": \"…\"
},
\"0\": {
\"essential\": \"i\",
\"analytics\": \"y\",
\"marketing\": \"v\"
}
}
},
\"reopen_preferences\": {
\"show_floating_link\": true,
\"preferences_link_href\": \"w\",
\"preferences_link_target\": \"architecto\",
\"invoke_window_function\": \"n\"
},
\"disabled_pages\": [
\"\\/checkout\",
\"\\/payment\"
],
\"share_consent_across_subdomains\": true
}"
const url = new URL(
"https://dev.permbot.net/api/sites/1/widget"
);
const params = {
"preview_locale": "tr",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"consent_location": "tr",
"locale": "sr_BA",
"copy": {
"en": {
"title": "Cookies",
"intro_html": "<p>We use cookies.<\/p>"
},
"0": {
"title": "z",
"intro_html": "m"
}
},
"cookie_policy_url": "https:\/\/example.com\/cookies",
"theme": {
"appearance": "dark",
"border_radius_px": 22,
"z_index": 67,
"colors": {
"primary": "z",
"primary_hover": "m",
"danger": "i",
"danger_hover": "y",
"surface": "v",
"text": "d",
"text_muted": "l",
"border": "j",
"switch_track_off": "n",
"switch_track_on": "i",
"shadow": "k",
"banner_max_width_px": 14
}
},
"banner": {
"show_reject_optional": true
},
"category_hints": {
"copy": {
"tr": {
"essential": "…",
"analytics": "…",
"marketing": "…"
},
"0": {
"essential": "i",
"analytics": "y",
"marketing": "v"
}
}
},
"reopen_preferences": {
"show_floating_link": true,
"preferences_link_href": "w",
"preferences_link_target": "architecto",
"invoke_window_function": "n"
},
"disabled_pages": [
"\/checkout",
"\/payment"
],
"share_consent_across_subdomains": true
};
fetch(url, {
method: "PATCH",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (200, success):
{
"data": {
"site_id": 1,
"settings": {
"theme": {
"appearance": "dark"
}
},
"resolved": {
"locale": "en"
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Reset widget settings to packaged defaults
requires authentication
Removes sites.settings.widget while preserving unrelated settings keys.
Example request:
curl --request DELETE \
"https://dev.permbot.net/api/sites/1/widget" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/sites/1/widget"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "DELETE",
headers,
}).then(response => response.json());Example response (200, success):
{
"data": {
"site_id": 1,
"settings": null
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Support tickets (panel)
Authenticated users can open and follow their own support requests.
GET api/support/tickets
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/support/tickets" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"per_page\": 1
}"
const url = new URL(
"https://dev.permbot.net/api/support/tickets"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"per_page": 1
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/support/tickets
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/support/tickets" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"subject\": \"b\",
\"message\": \"n\"
}"
const url = new URL(
"https://dev.permbot.net/api/support/tickets"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"subject": "b",
"message": "n"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/support/tickets/{ticketUid}
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://dev.permbot.net/api/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());Example response (401):
Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
{
"message": "Unauthenticated."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/support/tickets/{ticketUid}/messages
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/messages" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"message\": \"b\"
}"
const url = new URL(
"https://dev.permbot.net/api/support/tickets/BcECdBDA-CdED-bFEA-CbCE-BcCdeBfbbebc/messages"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"message": "b"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Support tickets (public guest)
Privacy-scoped endpoints for visitors without an account (e.g. KVKK requests). Message history is never exposed on these routes.
POST api/v1/support/guest
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/v1/support/guest" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"guest_name\": \"b\",
\"guest_email\": \"zbailey@example.net\",
\"subject\": \"i\",
\"message\": \"y\"
}"
const url = new URL(
"https://dev.permbot.net/api/v1/support/guest"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"guest_name": "b",
"guest_email": "zbailey@example.net",
"subject": "i",
"message": "y"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
GET api/v1/support/guest/reply
requires authentication
Example request:
curl --request GET \
--get "https://dev.permbot.net/api/v1/support/guest/reply" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"ticket_uid\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\",
\"token\": \"g\"
}"
const url = new URL(
"https://dev.permbot.net/api/v1/support/guest/reply"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"ticket_uid": "6ff8f7f6-1eb3-3525-be4a-3932c805afed",
"token": "g"
};
fetch(url, {
method: "GET",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Example response (422):
Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 20
x-ratelimit-remaining: 11
access-control-allow-origin: *
{
"message": "The Token field must be at least 32 characters.",
"errors": {
"token": [
"The Token field must be at least 32 characters."
]
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
POST api/v1/support/guest/reply
requires authentication
Example request:
curl --request POST \
"https://dev.permbot.net/api/v1/support/guest/reply" \
--header "Authorization: Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}" \
--header "Content-Type: application/json" \
--header "Accept: application/json" \
--data "{
\"ticket_uid\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\",
\"token\": \"g\",
\"message\": \"z\"
}"
const url = new URL(
"https://dev.permbot.net/api/v1/support/guest/reply"
);
const headers = {
"Authorization": "Bearer {SANCTUM_PERSONAL_ACCESS_TOKEN}",
"Content-Type": "application/json",
"Accept": "application/json",
};
let body = {
"ticket_uid": "6ff8f7f6-1eb3-3525-be4a-3932c805afed",
"token": "g",
"message": "z"
};
fetch(url, {
method: "POST",
headers,
body: JSON.stringify(body),
}).then(response => response.json());Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.