API reference
Every endpoint, generated from the OpenAPI document. Base URL: https://taseli.co.il/api/v1.
Workspace
The business a key opens.
The business this key opens
GET/workspace
| Returns | Type | |
|---|---|---|
id | string | |
name | string | |
slug | string | In the app's links. |
currency | string | |
plan | free starter pro agency | |
accounts | integer | Connected ad accounts. |
curl https://taseli.co.il/api/v1/workspace \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch("https://taseli.co.il/api/v1/workspace", {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": {
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"name": "Dan Plumbing",
"slug": "dan-plumbing",
"currency": "ILS",
"plan": "pro",
"accounts": 2
}
}Accounts
The connected Google, Meta and TikTok ad accounts, and their numbers.
List ad accounts
GET/accounts
| Query | Type | |
|---|---|---|
limit | integer | How many, from 1 to 100. Default 50. |
cursor | string | nextCursor from the previous page. |
| Returns | Type | |
|---|---|---|
id | string | |
name | string | |
platform | google meta tiktok | |
externalId | string | The platform's own id. |
currency | string | |
timezone | string | The account's time zone: its metrics' days end here. |
status | active syncing needs_reconnect suspended | |
readOnly | boolean | Nothing changes in it, even approved. |
goal | leads sales calls traffic | |
target | object | |
target.kind | cpa roas | |
target.value | number | Money for cpa, a ratio for roas. |
target.set | boolean | False: nobody set a target; value is the account's own cost per result standing in. |
lastSyncAt | string | |
budget | object | |
budget.monthly | number | |
budget.spentMtd | number | Spent this month. |
budget.forecast | number | Where the month ends at this pace. |
budget.set | boolean | False: no monthly budget set; monthly is the pace estimate. |
last28 | object | |
last28.cost | number | |
last28.conversions | number | |
last28.value | number | The conversion value the platform reports. 0 when it reports none. |
last28.clicks | integer | |
last28.impressions | integer | |
total | integer | How many in the whole list. |
nextCursor | string or null |
curl https://taseli.co.il/api/v1/accounts \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch("https://taseli.co.il/api/v1/accounts", {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": [
{
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"name": "Dan Plumbing Search",
"platform": "google",
"externalId": "123-456-7890",
"currency": "ILS",
"timezone": "Asia/Jerusalem",
"status": "active",
"readOnly": false,
"goal": "leads",
"target": {
"kind": "cpa",
"value": 85,
"set": true
},
"lastSyncAt": "2026-10-20T08:12:00.000Z",
"budget": {
"monthly": 6000,
"spentMtd": 2140.5,
"forecast": 5890,
"set": true
},
"last28": {
"cost": 5320.1,
"conversions": 61,
"value": 0,
"clicks": 1840,
"impressions": 41200
}
}
],
"total": 1,
"nextCursor": null
}One ad account
GET/accounts/{id}
| Path | Type | |
|---|---|---|
id | string | The account's Taseli id. Required. |
| Returns | Type | |
|---|---|---|
id | string | |
name | string | |
platform | google meta tiktok | |
externalId | string | The platform's own id. |
currency | string | |
timezone | string | The account's time zone: its metrics' days end here. |
status | active syncing needs_reconnect suspended | |
readOnly | boolean | Nothing changes in it, even approved. |
goal | leads sales calls traffic | |
target | object | |
target.kind | cpa roas | |
target.value | number | Money for cpa, a ratio for roas. |
target.set | boolean | False: nobody set a target; value is the account's own cost per result standing in. |
lastSyncAt | string | |
budget | object | |
budget.monthly | number | |
budget.spentMtd | number | Spent this month. |
budget.forecast | number | Where the month ends at this pace. |
budget.set | boolean | False: no monthly budget set; monthly is the pace estimate. |
last28 | object | |
last28.cost | number | |
last28.conversions | number | |
last28.value | number | The conversion value the platform reports. 0 when it reports none. |
last28.clicks | integer | |
last28.impressions | integer |
curl "https://taseli.co.il/api/v1/accounts/$ACCOUNT_ID" \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch(`https://taseli.co.il/api/v1/accounts/${ACCOUNT_ID}`, {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": {
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"name": "Dan Plumbing Search",
"platform": "google",
"externalId": "123-456-7890",
"currency": "ILS",
"timezone": "Asia/Jerusalem",
"status": "active",
"readOnly": false,
"goal": "leads",
"target": {
"kind": "cpa",
"value": 85,
"set": true
},
"lastSyncAt": "2026-10-20T08:12:00.000Z",
"budget": {
"monthly": 6000,
"spentMtd": 2140.5,
"forecast": 5890,
"set": true
},
"last28": {
"cost": 5320.1,
"conversions": 61,
"value": 0,
"clicks": 1840,
"impressions": 41200
}
}
}Daily metrics, or totals by campaign
GET/accounts/{id}/metrics
As synced from the platform once a day, in the account's currency and time zone. A day not synced yet is missing, never zero. At most 400 days per call. by=campaign gives the 200 campaigns that spent the most in the period; for one row per campaign per day, call it once per day.
| Path | Type | |
|---|---|---|
id | string | The account's Taseli id. Required. |
| Query | Type | |
|---|---|---|
from | string | First day, YYYY-MM-DD. Default: 29 days before to. |
to | string | Last day, YYYY-MM-DD. Default: today (UTC). |
by | day campaign | One row per day, or totals per campaign. Default day. |
| Returns | Type | |
|---|---|---|
account | string | |
currency | string | |
from | string | |
to | string | |
days | object[] | Optional. |
days[].date | string | |
days[].cost | number | |
days[].conversions | number | |
days[].value | number | |
days[].clicks | integer | |
days[].impressions | integer | |
totals | object | Optional. |
totals.cost | number | |
totals.conversions | number | |
totals.value | number | |
totals.clicks | integer | |
totals.impressions | integer | |
totals.costPerConversion | number or null | |
totals.ctr | number or null | |
campaigns | object[] | Optional. |
campaigns[].id | string | The campaign's Taseli id. |
campaigns[].name | string | |
campaigns[].cost | number | |
campaigns[].conversions | number | |
campaigns[].value | number | |
campaigns[].clicks | integer | |
campaigns[].impressions | integer | |
campaigns[].costPerConversion | number or null |
curl "https://taseli.co.il/api/v1/accounts/$ACCOUNT_ID/metrics?from=2026-10-01&to=2026-10-20&by=day" \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch(`https://taseli.co.il/api/v1/accounts/${ACCOUNT_ID}/metrics?from=2026-10-01&to=2026-10-20&by=day`, {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": {
"account": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"currency": "ILS",
"from": null,
"to": null,
"days": [
{
"date": "2026-10-19",
"cost": 182.4,
"conversions": 3,
"value": 0,
"clicks": 64,
"impressions": 1390
}
],
"totals": {
"cost": 182.4,
"conversions": 3,
"value": 0,
"clicks": 64,
"impressions": 1390,
"costPerConversion": 60.8,
"ctr": 4.6
}
}
}Proposals
Changes Taseli prepared, ran, watched or undid. The owner approves them in Taseli; approvalUrl is the link. Taseli keeps the latest 200 here.
List proposals by state
GET/proposals
| Query | Type | |
|---|---|---|
status | waiting active done all | waiting: awaiting approval, most valuable first. active: approved, executing or monitoring. done: kept, rolled_back, rejected, expired or failed. all. The last three are newest first. Default waiting. |
account | string | An account's id, name or platform id. |
limit | integer | How many, from 1 to 100. Default 20. |
cursor | string | nextCursor from the previous page. |
language | he ar en | Language of titles and texts. Default he. |
| Returns | Type | |
|---|---|---|
id | string | |
number | integer | The # the owner sees. |
status | awaiting_approval approved executing monitoring kept rolled_back rejected expired failed | |
kind | string | What it changes, for example budget_change, negative_keywords_add, entity_pause, bid_target_change, campaign_create. |
source | string | Who prepared it: audit, anomaly, rule, playbook, agent (Taseli's chat), mcp (an outside AI) or user. |
account | string | The account's name. |
campaign | string or null | |
title | string | |
why | string | |
monthlyValue | number | What Taseli expects it to be worth a month, in the account's currency. |
risk | low medium high | |
confidence | high medium low | |
changes | object[] | |
changes[].what | string | The campaign, keyword or ad. |
changes[].field | string | |
changes[].before | string | |
changes[].after | string | |
createdAt | string | |
decidedAt | string or null | |
decidedVia | string or null | |
executedAt | string or null | |
watch | object or null | |
watch.day | integer | Day of the watch. |
watch.days | integer | Length of the watch. |
rolledBackAt | string or null | |
approvalUrl | string | Where the owner approves it, in Taseli. |
total | integer | How many in the whole list. |
nextCursor | string or null |
curl "https://taseli.co.il/api/v1/proposals?status=waiting&language=en" \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch("https://taseli.co.il/api/v1/proposals?status=waiting&language=en", {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": [
{
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"number": 214,
"status": "awaiting_approval",
"kind": "negative_keywords_add",
"source": "audit",
"account": "Dan Plumbing Search",
"campaign": "Emergency plumber",
"title": "Block 12 searches that spend without leads",
"why": "They took ₪640 in 28 days with no lead.",
"monthlyValue": 680,
"risk": "low",
"confidence": "high",
"changes": [
{
"what": "Emergency plumber",
"field": "Blocked searches",
"before": "48",
"after": "60"
}
],
"createdAt": "2026-10-20T08:12:00.000Z",
"decidedAt": null,
"decidedVia": null,
"executedAt": null,
"watch": null,
"rolledBackAt": null,
"approvalUrl": "https://taseli.co.il/en/app/dan-plumbing/proposals/0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90"
}
],
"total": 1,
"nextCursor": null
}One proposal in full
GET/proposals/{id}
Up to 50 changes; the list shows 5 per proposal. Among the workspace's latest 200.
| Path | Type | |
|---|---|---|
id | string | The proposal's id. Required. |
| Query | Type | |
|---|---|---|
language | he ar en | Language of titles and texts. Default he. |
| Returns | Type | |
|---|---|---|
id | string | |
number | integer | The # the owner sees. |
status | awaiting_approval approved executing monitoring kept rolled_back rejected expired failed | |
kind | string | What it changes, for example budget_change, negative_keywords_add, entity_pause, bid_target_change, campaign_create. |
source | string | Who prepared it: audit, anomaly, rule, playbook, agent (Taseli's chat), mcp (an outside AI) or user. |
account | string | The account's name. |
campaign | string or null | |
title | string | |
why | string | |
monthlyValue | number | What Taseli expects it to be worth a month, in the account's currency. |
risk | low medium high | |
confidence | high medium low | |
changes | object[] | |
changes[].what | string | The campaign, keyword or ad. |
changes[].field | string | |
changes[].before | string | |
changes[].after | string | |
createdAt | string | |
decidedAt | string or null | |
decidedVia | string or null | |
executedAt | string or null | |
watch | object or null | |
watch.day | integer | Day of the watch. |
watch.days | integer | Length of the watch. |
rolledBackAt | string or null | |
approvalUrl | string | Where the owner approves it, in Taseli. |
curl "https://taseli.co.il/api/v1/proposals/$PROPOSAL_ID?language=en" \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch(`https://taseli.co.il/api/v1/proposals/${PROPOSAL_ID}?language=en`, {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": {
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"number": 214,
"status": "awaiting_approval",
"kind": "negative_keywords_add",
"source": "audit",
"account": "Dan Plumbing Search",
"campaign": "Emergency plumber",
"title": "Block 12 searches that spend without leads",
"why": "They took ₪640 in 28 days with no lead.",
"monthlyValue": 680,
"risk": "low",
"confidence": "high",
"changes": [
{
"what": "Emergency plumber",
"field": "Blocked searches",
"before": "48",
"after": "60"
}
],
"createdAt": "2026-10-20T08:12:00.000Z",
"decidedAt": null,
"decidedVia": null,
"executedAt": null,
"watch": null,
"rolledBackAt": null,
"approvalUrl": "https://taseli.co.il/en/app/dan-plumbing/proposals/0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90"
}
}Activity
The latest 200 things that happened in the accounts.
What happened in the accounts, newest first
GET/activity
| Query | Type | |
|---|---|---|
limit | integer | How many, from 1 to 100. Default 50. |
cursor | string | nextCursor from the previous page. |
language | he ar en | Language of titles and texts. Default he. |
| Returns | Type | |
|---|---|---|
id | string | |
at | string | |
account | string | The account's name. |
actor | taseli user external google | |
kind | executed kept rolled_back approved rejected external_change sync alert access_changed | |
text | string | |
detail | string or null | |
entity | string or null | |
via | string or null | |
proposalId | string or null | |
total | integer | How many in the whole list. |
nextCursor | string or null |
curl "https://taseli.co.il/api/v1/activity?limit=20&language=en" \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch("https://taseli.co.il/api/v1/activity?limit=20&language=en", {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": [
{
"id": "a-48213",
"at": "2026-10-20T08:12:00.000Z",
"account": "Dan Plumbing Search",
"actor": "taseli",
"kind": "executed",
"text": "Blocked 12 searches.",
"detail": null,
"entity": "Emergency plumber",
"via": null,
"proposalId": null
}
],
"total": 1,
"nextCursor": null
}Creatives
Each picture and video with its own last-30-day results.
Pictures and videos with their results and verdict
GET/creatives
Highest spend first, from the 300 highest. No cursor: shown and of say how much of the list came back. An account filter leaves out creatives that belong to no account (uploads, generated pictures). With nothing to show, the answer is only a note.
| Query | Type | |
|---|---|---|
account | string | An account's id, name or platform id. |
verdict | good ok weak untested unused new | Only this verdict. |
kind | image video | Only pictures or videos. |
limit | integer | How many, from 1 to 100. Default 15. |
language | he ar en | Language of titles and texts. Default he. |
| Returns | Type | |
|---|---|---|
window | string | Optional. |
verdicts | object | How many of each verdict. Optional. |
note | string | A caveat on the numbers, or the only field when there is nothing to show. |
shown | integer | Optional. |
of | integer | Optional. |
creatives | object[] | Optional. |
creatives[].id | string | |
creatives[].title | string | |
creatives[].kind | image video | |
creatives[].shows | string | What's in it. Optional. |
creatives[].seconds | integer | A video's length. Optional. |
creatives[].account | string | The account's name, or the source of a creative with no account. Optional. |
creatives[].verdict | good ok weak untested unused new | Among the account's own creatives. Optional. |
creatives[].why | string | Why it's weak. Optional. |
creatives[].live | boolean | Seen in the last 3 days. |
creatives[].runsOn | string[] | The placements it runs on. Optional. |
creatives[].spend | string | Formatted with its currency. Optional. |
creatives[].results | number | Optional. |
creatives[].impressions | number | Optional. |
creatives[].ctr | number | Percent. Optional. |
creatives[].perResult | string | Formatted with its currency. Optional. |
creatives[].offer | string | Whether it matches the current offer. Optional. |
creatives[].offerWhy | string | Optional. |
creatives[].watched | object | For videos: the hook, the offer, voice, music, on-screen words and the start of the transcript. Optional. |
curl "https://taseli.co.il/api/v1/creatives?verdict=weak&limit=50&language=en" \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch("https://taseli.co.il/api/v1/creatives?verdict=weak&limit=50&language=en", {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": {
"window": "last 30 days",
"verdicts": {
"good": 2,
"weak": 1
},
"note": "Per-creative results on Meta are a lower bound; spend, impressions and clicks are exact.",
"shown": 1,
"of": 3,
"creatives": [
{
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"title": "Plumber at the door, 24/7",
"kind": "image",
"account": "Dan Plumbing Meta",
"verdict": "good",
"live": true,
"spend": "₪412.00",
"results": 9,
"impressions": 15210,
"ctr": 1.8,
"perResult": "₪45.78"
}
]
}
}Competitors
Where the feature is on for the business. Otherwise 404 not_enabled.
Competitors Taseli watches
GET/competitors
| Query | Type | |
|---|---|---|
language | he ar en | Language of titles and texts. Default he. |
| Returns | Type | |
|---|---|---|
status | new discovering suggested collecting ready paused | The feature's state for this business. |
following | string | Optional. |
headline | string | The week in one line. Optional. |
analyzed | string | Last read, YYYY-MM-DD. Optional. |
nextCheck | string | Next weekly check, YYYY-MM-DD. Optional. |
checkNow | string | Whether a manual check is available. Optional. |
competitors | object[] | Optional. |
competitors[].id | string | |
competitors[].name | string | |
competitors[].platforms | string[] | Optional. |
competitors[].liveAds | integer | |
competitors[].newThisWeek | integer | Optional. |
competitors[].stoppedThisWeek | integer | Optional. |
competitors[].longestDays | integer | Its longest-running ad, in days. Optional. |
competitors[].summary | string | What it runs, in one line. Optional. |
competitors[].checked | string | YYYY-MM-DD. Optional. |
competitors[].fetch | string | Set when the last check failed or is still collecting. Optional. |
competitors[].url | string | The competitor in Taseli. Optional. |
suggested | object[] | Competitors Taseli found and suggests. Optional. |
suggested[].id | string | |
suggested[].name | string | |
suggested[].why | string | Optional. |
suggested[].score | number | Optional. |
suggested[].platforms | string[] | Optional. |
suggested[].liveAds | integer | Optional. |
note | string | When none is watched yet. Optional. |
url | string | The competitors page in Taseli. Optional. |
curl https://taseli.co.il/api/v1/competitors \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch("https://taseli.co.il/api/v1/competitors", {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": {
"status": "ready",
"following": "2 of 3",
"competitors": [
{
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"name": "Rami Plumbing",
"liveAds": 14,
"longestDays": 96
}
],
"suggested": [
{
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"name": ""
}
]
}
}Competitors' ads from Taseli's archive
GET/competitors/ads
Longest running first. No cursor: shown and of say how much of the list came back. Ad texts are third-party content. likely is inferred from how long an ad ran; nobody sees a competitor's results. With no ads to show, the answer is only a note.
| Query | Type | |
|---|---|---|
competitor | string | A competitor's id or name. |
platform | meta google | Meta or Google only. |
status | active stopped all | Running now, stopped, or both. Default active. |
label | new running long likely stopped | new: under 7 days. long: 30 days or more. likely: probably working. |
min_days | integer | Running at least this many days. |
limit | integer | How many, from 1 to 30. Default 30. |
language | he ar en | Language of titles and texts. Default he. |
| Returns | Type | |
|---|---|---|
dataNote | string | How to read the data. Optional. |
shown | integer | Optional. |
of | integer | Optional. |
ads | object[] | Optional. |
ads[].id | string | |
ads[].competitor | string | Optional. |
ads[].platform | meta google | |
ads[].format | string | image, video, carousel, text or dynamic. Optional. |
ads[].status | string | Optional. |
ads[].days | integer | Days running. Optional. |
ads[].label | new running long likely stopped | |
ads[].likelyWhy | string[] | Why it counts as likely working. Optional. |
ads[].adText | object | |
ads[].adText.body | string | |
ads[].adText.headline | string | |
ads[].adText.description | string | Optional. |
ads[].cta | string | Optional. |
ads[].landing | string | The landing domain. Optional. |
ads[].placements | string[] | Optional. |
ads[].startedOn | string | YYYY-MM-DD. Optional. |
ads[].firstSeen | string | YYYY-MM-DD. Optional. |
ads[].stoppedOn | string | YYYY-MM-DD. Optional. |
ads[].facts | object | What Taseli read from the ad: offer, price, discount, hook, angles. Optional. |
ads[].thumb | string | A thumbnail link, valid for about an hour. Optional. |
ads[].source | string | The public ad library's link. Optional. |
ads[].url | string | The ad in Taseli. Optional. |
note | string | When there are no ads to show. Optional. |
curl "https://taseli.co.il/api/v1/competitors/ads?label=likely&language=en" \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch("https://taseli.co.il/api/v1/competitors/ads?label=likely&language=en", {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": {
"shown": 1,
"of": 14,
"ads": [
{
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"competitor": "Rami Plumbing",
"platform": "meta",
"format": "image",
"status": "active",
"days": 96,
"label": "likely",
"adText": {
"body": "A plumber at your door in 30 minutes.",
"headline": "24/7 plumber"
},
"landing": "rami-plumbing.example"
}
]
}
}Webhooks
Owners and admins only, with a personal key that isn't read-only (a connected app's token can't manage webhooks).
List webhooks
GET/webhooks
| Returns | Type | |
|---|---|---|
id | string | |
url | string | |
events | string[] | |
language | he ar en | |
active | boolean | False: it sends nothing. See pausedReason. |
pausedReason | key member or null | |
failures | integer | Failed attempts in a row. At 25 it switches off. |
lastStatus | integer or null | |
lastError | string or null | |
lastDeliveryAt | string or null | |
createdAt | string |
curl https://taseli.co.il/api/v1/webhooks \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch("https://taseli.co.il/api/v1/webhooks", {
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": [
{
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"url": "https://crm.example.com/hooks/taseli",
"events": [
""
],
"language": "en",
"active": true,
"pausedReason": null,
"failures": 0,
"lastStatus": 200,
"lastError": null,
"lastDeliveryAt": null,
"createdAt": "2026-10-20T08:12:00.000Z"
}
]
}Create a webhook
POST/webhooks
Up to 5 per workspace. The response carries the signing secret once; it isn't shown again (delete and recreate to replace it). Not idempotent: after a timeout, list webhooks before retrying. Deliveries are signed with HMAC-SHA256; reject signatures older than 300 seconds. See /developers/webhooks.
| Body | Type | |
|---|---|---|
url | string | A public https address on the default port. |
events | proposal.created change.applied change.undone verdict.recorded[] | Default: all of them. Optional. |
language | he ar en | Language of titles and texts in the events. Optional. |
| Returns | Type | |
|---|---|---|
id | string | |
url | string | |
events | string[] | |
language | he ar en | |
active | boolean | False: it sends nothing. See pausedReason. |
pausedReason | key member or null | |
failures | integer | Failed attempts in a row. At 25 it switches off. |
lastStatus | integer or null | |
lastError | string or null | |
lastDeliveryAt | string or null | |
createdAt | string | |
secret | string | Shown once. |
curl -X POST https://taseli.co.il/api/v1/webhooks \
-H "Authorization: Bearer $TASELI_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://crm.example.com/hooks/taseli","language":"en"}'const res = await fetch("https://taseli.co.il/api/v1/webhooks", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"url":"https://crm.example.com/hooks/taseli","language":"en"}),
});
const { data } = await res.json();{
"data": {
"id": "0b6f3c1e-7a42-4c55-9b1d-2f6e8a1c4d90",
"url": "https://crm.example.com/hooks/taseli",
"events": [
""
],
"language": "en",
"active": true,
"pausedReason": null,
"failures": 0,
"lastStatus": 200,
"lastError": null,
"lastDeliveryAt": null,
"createdAt": "2026-10-20T08:12:00.000Z",
"secret": "whsec_G7pQ0mYcVx2u4Tn8Zk1Rb6Ld3Ha9Ws5Je0Fy7Ci2Mo4"
}
}Delete a webhook
DELETE/webhooks/{id}
| Path | Type | |
|---|---|---|
id | string | The webhook's id. Required. |
Returns 204 with no body.
curl -X DELETE "https://taseli.co.il/api/v1/webhooks/$WEBHOOK_ID" \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch(`https://taseli.co.il/api/v1/webhooks/${WEBHOOK_ID}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
console.log(res.status); // 204Send one signed webhook.test now
POST/webhooks/{id}/test
Answers what the receiver answered. A test that lands switches back on a webhook that failures switched off. One paused for its key or its maker stays paused.
| Path | Type | |
|---|---|---|
id | string | The webhook's id. Required. |
| Returns | Type | |
|---|---|---|
delivered | boolean | A 2xx came back. |
status | integer | The receiver's status. 0: none. |
error | string or null |
curl -X POST "https://taseli.co.il/api/v1/webhooks/$WEBHOOK_ID/test" \
-H "Authorization: Bearer $TASELI_KEY"const res = await fetch(`https://taseli.co.il/api/v1/webhooks/${WEBHOOK_ID}/test`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TASELI_KEY}`,
},
});
const { data } = await res.json();{
"data": {
"delivered": true,
"status": 200,
"error": null
}
}