API reference
Register your own signal
Registers a signal you run yourself, or updates it: the same key again changes what you send and keeps what you leave out. It shows on the Signals page of mySDR right away. After every check, report it with POST /agent-signals/{key}/hits. At most 50 per organization.
A signal your agent runs itself, with its own tools: hiring spikes on careers pages, posts on X, a newsletter, a list in the CRM. Register it and the user sees it on the Signals page of mySDR, next to the signals mySDR runs: what it watches, where, how often, when you last checked and what it caught. mySDR does not run, schedule or check it: it shows what you report. These routes are the tools save_agent_signal, log_signal_hits, list_agent_signals and delete_agent_signal of the assistant server.
Authentication
Send Authorization: Bearer gtk_…. Create the key under Connect assistant → API keys. Every gtk_ key can call these routes, also while the Signals API is closed. A missing, invalid or revoked key is 401.
Body parameters
keystring· required — Your own name for the signal: lowercase letters, digits and_, starting with a letter, up to 40 characters (Hiring spikebecomeshiring_spike). Use the same key every time.namestring— As the user sees it on Signals, up to 100 characters, without|. Required the first time.descriptionstring | null— What it watches and why that matters, up to 500 characters.nullclears it.sourcestring | null— Where you look, in words ("Careers pages", "X"), up to 80 characters.source_urlstring | null— A link to that source (https://…), e.g. a saved search.schedulestring | null— How often you check. Only shown: mySDR plans nothing. One of:hourly,daily,weekly,monthly,once,on_demand.statusstring—paused= you stop running it until it isactiveagain; a paused signal takes no checks. Defaultactive. One of:active,paused.next_check_atstring | null— When you check next: a date (2026-10-27, 09:00 Brussels time) or an ISO time. Later than that, the card says the check is overdue.
Response
objectstring· required — Alwaysagent_signal. One of:agent_signal.keystring· required — Your own name for it: lowercase letters, digits and_.namestring· required — As the user sees it.descriptionstring | null· required — What it watches.sourcestring | null· required — Where you look.source_urlstring | null· required — A link to that source.schedulestring | null· required — How often you check. One of:hourly,daily,weekly,monthly,once,on_demand.statusstring· required —activeorpaused. One of:active,paused.last_checked_atstring | null· required — When you last reported a check.next_check_atstring | null· required — When you said you check next.check_overdueboolean· required — True when the signal is active andnext_check_atis more than an hour ago: the user sees "Check overdue".last_check_notestring | null· required — What your last check did.caughtobject· required —leadsandcompanies: how many people and companies it caught, each counted once.last_hit_atstring | null· required — When it last caught something.viastring | null· required — The name of the key that last registered it or reported a check ("Grok Bot").created_atstring· required — When it was registered.updated_atstring· required — When it last changed.results_urlstring· required — The Leads or Companies table in mySDR on this signal (where it caught the most).createdboolean· required — True when this call registered it; false when it updated one.dashboard_urlstring· required — The Signals page in mySDR.
Credits
Free. This call never uses credits.
Errors
- 400
invalid_request— Nokey, a key that is not valid, nonamethe first time, a value that is too long or not one of its values (paramnames it), or an unknown field. - 409
invalid_state— The organization has 50 own signals already: delete one first. - 503
service_unavailable— Own signals are not available in this environment yet. - 409
invalid_state— The key has no user behind it, so mySDR cannot record who did it. - 401
authentication_error— The Authorization header is missing, or the key is unknown or revoked. - 403
permission_error— API access is not part of your plan, or your account is suspended. - 429
rate_limit_error— More than 60 requests per minute, or more than 3 at the same time, on one key. Wait for the Retry-After header. - 503
service_unavailable— The API is temporarily unavailable. Retry later. - 500
internal_error— Something went wrong on our side.
Example
cURL
curl -X POST "https://mysdr.app/api/v1/agent-signals" \
-H "Authorization: Bearer $MYSDR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"key": "hiring_spike",
"name": "Hiring spike on careers pages",
"description": "Companies whose careers page lists at least 10 open roles, up from fewer than 5.",
"source": "Careers pages",
"schedule": "daily",
"next_check_at": "2026-10-26"
}'
JavaScript
const response = await fetch('https://mysdr.app/api/v1/agent-signals', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MYSDR_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
"key": "hiring_spike",
"name": "Hiring spike on careers pages",
"description": "Companies whose careers page lists at least 10 open roles, up from fewer than 5.",
"source": "Careers pages",
"schedule": "daily",
"next_check_at": "2026-10-26"
})
});
const body = await response.json();
Python
import json
import os
import urllib.request
payload = {
"key": "hiring_spike",
"name": "Hiring spike on careers pages",
"description": "Companies whose careers page lists at least 10 open roles, up from fewer than 5.",
"source": "Careers pages",
"schedule": "daily",
"next_check_at": "2026-10-26"
}
request = urllib.request.Request(
"https://mysdr.app/api/v1/agent-signals",
headers={
"Authorization": f"Bearer {os.environ['MYSDR_API_KEY']}",
"Content-Type": "application/json"
},
data=json.dumps(payload).encode(),
method="POST",
)
with urllib.request.urlopen(request) as response:
body = json.load(response)
Example response
{
"object": "agent_signal",
"key": "hiring_spike",
"name": "Hiring spike on careers pages",
"description": "Companies whose careers page lists at least 10 open roles, up from fewer than 5.",
"source": "Careers pages",
"source_url": null,
"schedule": "daily",
"status": "active",
"last_checked_at": "2026-10-25T07:00:00.000Z",
"next_check_at": "2026-10-26T08:00:00.000Z",
"check_overdue": false,
"last_check_note": "140 careers pages, 3 spikes",
"caught": {
"leads": 0,
"companies": 9
},
"last_hit_at": "2026-10-25T07:00:00.000Z",
"via": "Grok Bot",
"created_at": "2026-10-20T08:00:00.000Z",
"updated_at": "2026-10-25T07:00:00.000Z",
"results_url": "https://mysdr.app/en/gtm/companies?signal=Hiring+spike+on+careers+pages",
"created": true,
"dashboard_url": "https://mysdr.app/en/gtm/signals"
}