curl -X POST https://api.up2data.ai/v1/signals/bulk \
-H "X-API-Key: $UP2DATA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: champions-import-2026-07" \
-d '{
"template": {
"name_prefix": "Job change",
"tags": ["champions", "q3-pipeline"],
"schedule": { "interval": "1d" },
"criteria": { "mode": "field_change", "fields": ["headline", "position", "company"] }
},
"targets": [
{ "type": "profile", "linkedin_url": "https://linkedin.com/in/a" },
{ "type": "profile", "linkedin_url": "https://linkedin.com/in/b" }
]
}'
resp = requests.post(
"https://api.up2data.ai/v1/signals/bulk",
headers={"X-API-Key": UP2DATA_API_KEY, "Idempotency-Key": "champions-import-2026-07"},
json={
"template": {
"name_prefix": "Job change",
"tags": ["champions"],
"schedule": {"interval": "1d"},
"criteria": {"mode": "field_change", "fields": ["headline", "position", "company"]},
},
"targets": [{"type": "profile", "linkedin_url": u} for u in urls],
},
)
print(resp.json()["data"]["estimated_monthly_credits"])
{
"data": {
"created": 998,
"rejected": [
{ "linkedin_url": "https://linkedin.com/in/bad-url", "reason": "invalid_url" },
{ "linkedin_url": "https://linkedin.com/in/dupe", "reason": "duplicate_target" }
],
"estimated_monthly_credits": 29940,
"signals": [
{ "id": "sig_a1", "name": "Job change — linkedin.com/in/a", "tags": ["champions", "q3-pipeline"], "status": "active" }
]
},
"meta": { "creditsUsed": 0, "billed": false, "reason": "bulk_created", "requestId": "req_bk20amx1" }
}
Signals
Bulk create Signals
One template × up to 1,000 targets → a fleet of Signals in one call.
POST
/
v1
/
signals
/
bulk
curl -X POST https://api.up2data.ai/v1/signals/bulk \
-H "X-API-Key: $UP2DATA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: champions-import-2026-07" \
-d '{
"template": {
"name_prefix": "Job change",
"tags": ["champions", "q3-pipeline"],
"schedule": { "interval": "1d" },
"criteria": { "mode": "field_change", "fields": ["headline", "position", "company"] }
},
"targets": [
{ "type": "profile", "linkedin_url": "https://linkedin.com/in/a" },
{ "type": "profile", "linkedin_url": "https://linkedin.com/in/b" }
]
}'
resp = requests.post(
"https://api.up2data.ai/v1/signals/bulk",
headers={"X-API-Key": UP2DATA_API_KEY, "Idempotency-Key": "champions-import-2026-07"},
json={
"template": {
"name_prefix": "Job change",
"tags": ["champions"],
"schedule": {"interval": "1d"},
"criteria": {"mode": "field_change", "fields": ["headline", "position", "company"]},
},
"targets": [{"type": "profile", "linkedin_url": u} for u in urls],
},
)
print(resp.json()["data"]["estimated_monthly_credits"])
{
"data": {
"created": 998,
"rejected": [
{ "linkedin_url": "https://linkedin.com/in/bad-url", "reason": "invalid_url" },
{ "linkedin_url": "https://linkedin.com/in/dupe", "reason": "duplicate_target" }
],
"estimated_monthly_credits": 29940,
"signals": [
{ "id": "sig_a1", "name": "Job change — linkedin.com/in/a", "tags": ["champions", "q3-pipeline"], "status": "active" }
]
},
"meta": { "creditsUsed": 0, "billed": false, "reason": "bulk_created", "requestId": "req_bk20amx1" }
}
Cost: Free to create · each Signal’s checks bill per the standard pay-per-check rules
The fleet primitive: watch your whole book of business without 1,000 API calls. Every created Signal shares the template’s schedule, criteria, notify and tags — manage them collectively by tag afterwards.
How Signals work
Signals are scheduled change monitoring, billed per check. See what you can watch and how it’s priced.
object
required
Show Template fields
Show Template fields
string
Each Signal is named
{name_prefix} — {target url}.string[]
Applied to every created Signal — your bulk-management handle.
string
Optional platform attribution key applied to every created Signal.
object
Opaque JSON bag copied onto every created Signal (and later Triggers / webhooks).
object
Omit to use the account default webhook — the usual pattern for fleets.
object[]
required
Up to 1,000 entries:
{ "type": "profile", "linkedin_url": "…" } each.string
Retried submissions with the same key return the original result instead of duplicating the fleet.
Response
integer
Signals created.
object[]
Invalid targets with reasons — the rest of the batch still succeeds.
integer
Combined burn for the whole fleet.
object[]
The created Signal objects.
curl -X POST https://api.up2data.ai/v1/signals/bulk \
-H "X-API-Key: $UP2DATA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: champions-import-2026-07" \
-d '{
"template": {
"name_prefix": "Job change",
"tags": ["champions", "q3-pipeline"],
"schedule": { "interval": "1d" },
"criteria": { "mode": "field_change", "fields": ["headline", "position", "company"] }
},
"targets": [
{ "type": "profile", "linkedin_url": "https://linkedin.com/in/a" },
{ "type": "profile", "linkedin_url": "https://linkedin.com/in/b" }
]
}'
resp = requests.post(
"https://api.up2data.ai/v1/signals/bulk",
headers={"X-API-Key": UP2DATA_API_KEY, "Idempotency-Key": "champions-import-2026-07"},
json={
"template": {
"name_prefix": "Job change",
"tags": ["champions"],
"schedule": {"interval": "1d"},
"criteria": {"mode": "field_change", "fields": ["headline", "position", "company"]},
},
"targets": [{"type": "profile", "linkedin_url": u} for u in urls],
},
)
print(resp.json()["data"]["estimated_monthly_credits"])
{
"data": {
"created": 998,
"rejected": [
{ "linkedin_url": "https://linkedin.com/in/bad-url", "reason": "invalid_url" },
{ "linkedin_url": "https://linkedin.com/in/dupe", "reason": "duplicate_target" }
],
"estimated_monthly_credits": 29940,
"signals": [
{ "id": "sig_a1", "name": "Job change — linkedin.com/in/a", "tags": ["champions", "q3-pipeline"], "status": "active" }
]
},
"meta": { "creditsUsed": 0, "billed": false, "reason": "bulk_created", "requestId": "req_bk20amx1" }
}
Prefer one Signal with a
profile_list target when you want one webhook stream and one estimate for the whole list; prefer bulk-created individual Signals when you need per-person pause/delete and per-person spend attribution. Same check pricing either way.