curl --request POST \
--url https://api.tamtam.ai/api/v2/job-posting-signals \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"description": "<string>",
"filters": "<unknown>",
"is_enabled": true,
"max_postings_analyzed": 25,
"name": "<string>",
"persona_ids": [
"<string>"
],
"use_cases": [
{
"name": "<string>",
"prompt": "<string>"
}
]
}
'import requests
url = "https://api.tamtam.ai/api/v2/job-posting-signals"
payload = {
"description": "<string>",
"filters": "<unknown>",
"is_enabled": True,
"max_postings_analyzed": 25,
"name": "<string>",
"persona_ids": ["<string>"],
"use_cases": [
{
"name": "<string>",
"prompt": "<string>"
}
]
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
description: '<string>',
filters: '<unknown>',
is_enabled: true,
max_postings_analyzed: 25,
name: '<string>',
persona_ids: ['<string>'],
use_cases: [{name: '<string>', prompt: '<string>'}]
})
};
fetch('https://api.tamtam.ai/api/v2/job-posting-signals', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tamtam.ai/api/v2/job-posting-signals",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'description' => '<string>',
'filters' => '<unknown>',
'is_enabled' => true,
'max_postings_analyzed' => 25,
'name' => '<string>',
'persona_ids' => [
'<string>'
],
'use_cases' => [
[
'name' => '<string>',
'prompt' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.tamtam.ai/api/v2/job-posting-signals"
payload := strings.NewReader("{\n \"description\": \"<string>\",\n \"filters\": \"<unknown>\",\n \"is_enabled\": true,\n \"max_postings_analyzed\": 25,\n \"name\": \"<string>\",\n \"persona_ids\": [\n \"<string>\"\n ],\n \"use_cases\": [\n {\n \"name\": \"<string>\",\n \"prompt\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.tamtam.ai/api/v2/job-posting-signals")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"<string>\",\n \"filters\": \"<unknown>\",\n \"is_enabled\": true,\n \"max_postings_analyzed\": 25,\n \"name\": \"<string>\",\n \"persona_ids\": [\n \"<string>\"\n ],\n \"use_cases\": [\n {\n \"name\": \"<string>\",\n \"prompt\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tamtam.ai/api/v2/job-posting-signals")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"description\": \"<string>\",\n \"filters\": \"<unknown>\",\n \"is_enabled\": true,\n \"max_postings_analyzed\": 25,\n \"name\": \"<string>\",\n \"persona_ids\": [\n \"<string>\"\n ],\n \"use_cases\": [\n {\n \"name\": \"<string>\",\n \"prompt\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"is_enabled": true,
"job_posting_kind": "<string>",
"kind": "<string>",
"name": "<string>",
"notes": [
"<string>"
],
"use_cases": [
"<string>"
],
"used_by_program_count": 123
}{
"detail": "Property foo is required but is missing.",
"errors": [
{
"location": "<string>",
"message": "<string>",
"value": "<unknown>"
}
],
"instance": "https://example.com/error-log/abc123",
"status": 400,
"title": "Bad Request",
"type": "https://example.com/errors/example"
}Create a job posting signal
A standing search over public job postings: who is hiring for X, who is adopting technology Y, which companies are building a Z team. Hiring is the earliest public evidence of a budget being spent.
Two ways to call it. Described: pass description alone, your own sentence or paragraph about what to catch and why it matters, and an AI drafts the search net, the use-cases and the judge prompts. The response carries the drafter’s notes, its assumptions and what it could not resolve; read them, because a signal drafted on a wrong assumption searches for the wrong thing quietly. Costs one AI call. Explicit: pass kind and filters, the provider’s own search block as an object. An unknown filter key is a 422 listing the valid ones, never a silently dropped field.
The kinds: technology needs one of job_technology_slug_or (in job_filters), job_description_contains_or, tech_filters.technology_slug_or or tech_filters.technology_category_slug_or; hiring_role needs persona_ids or one of job_title_or, job_title_pattern_or, job_description_contains_or in job_filters; use_case_analysis needs use_cases and at least one company or job filter to bound the search.
Cost when it runs: per posting judged.
Creating a signal starts nothing and bills nothing. A signal runs only when a lead generation program picks it: Start a lead generation run sweeps it now and records a program you can put on a schedule under Settings > Signals > Lead generation. List signals reports used_by_program_count per signal; zero means it is defined and never runs. List first, so you do not create a second signal over a question you already ask: duplicates bill twice and split the leads across two names.
curl --request POST \
--url https://api.tamtam.ai/api/v2/job-posting-signals \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"description": "<string>",
"filters": "<unknown>",
"is_enabled": true,
"max_postings_analyzed": 25,
"name": "<string>",
"persona_ids": [
"<string>"
],
"use_cases": [
{
"name": "<string>",
"prompt": "<string>"
}
]
}
'import requests
url = "https://api.tamtam.ai/api/v2/job-posting-signals"
payload = {
"description": "<string>",
"filters": "<unknown>",
"is_enabled": True,
"max_postings_analyzed": 25,
"name": "<string>",
"persona_ids": ["<string>"],
"use_cases": [
{
"name": "<string>",
"prompt": "<string>"
}
]
}
headers = {
"Authorization": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
description: '<string>',
filters: '<unknown>',
is_enabled: true,
max_postings_analyzed: 25,
name: '<string>',
persona_ids: ['<string>'],
use_cases: [{name: '<string>', prompt: '<string>'}]
})
};
fetch('https://api.tamtam.ai/api/v2/job-posting-signals', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.tamtam.ai/api/v2/job-posting-signals",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'description' => '<string>',
'filters' => '<unknown>',
'is_enabled' => true,
'max_postings_analyzed' => 25,
'name' => '<string>',
'persona_ids' => [
'<string>'
],
'use_cases' => [
[
'name' => '<string>',
'prompt' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <api-key>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.tamtam.ai/api/v2/job-posting-signals"
payload := strings.NewReader("{\n \"description\": \"<string>\",\n \"filters\": \"<unknown>\",\n \"is_enabled\": true,\n \"max_postings_analyzed\": 25,\n \"name\": \"<string>\",\n \"persona_ids\": [\n \"<string>\"\n ],\n \"use_cases\": [\n {\n \"name\": \"<string>\",\n \"prompt\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.tamtam.ai/api/v2/job-posting-signals")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"description\": \"<string>\",\n \"filters\": \"<unknown>\",\n \"is_enabled\": true,\n \"max_postings_analyzed\": 25,\n \"name\": \"<string>\",\n \"persona_ids\": [\n \"<string>\"\n ],\n \"use_cases\": [\n {\n \"name\": \"<string>\",\n \"prompt\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tamtam.ai/api/v2/job-posting-signals")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"description\": \"<string>\",\n \"filters\": \"<unknown>\",\n \"is_enabled\": true,\n \"max_postings_analyzed\": 25,\n \"name\": \"<string>\",\n \"persona_ids\": [\n \"<string>\"\n ],\n \"use_cases\": [\n {\n \"name\": \"<string>\",\n \"prompt\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"is_enabled": true,
"job_posting_kind": "<string>",
"kind": "<string>",
"name": "<string>",
"notes": [
"<string>"
],
"use_cases": [
"<string>"
],
"used_by_program_count": 123
}{
"detail": "Property foo is required but is missing.",
"errors": [
{
"location": "<string>",
"message": "<string>",
"value": "<unknown>"
}
],
"instance": "https://example.com/error-log/abc123",
"status": 400,
"title": "Bad Request",
"type": "https://example.com/errors/example"
}Authorizations
Account API key passed in the Authorization header
Query Parameters
Target account UUID. Required for staff callers; ignored for customer API keys.
Body
DESCRIBED path: your own sentence or paragraph about what the signal should catch, with context on why it matters. An AI drafts the whole definition from it, and the response carries its notes. Pass this alone, or kind and filters instead.
EXPLICIT path: the provider's search block as an object: company facets at the top level (company_country_code_or, industry_id_or, min_employee_count_or_null, ...), plus nested job_filters (job_title_or, job_title_pattern_or, job_country_code_or, job_description_contains_or, ...) and tech_filters (technology_slug_or, technology_category_slug_or, ...). An unknown key is a 422 listing the valid ones, never a silently dropped filter.
Defaults to true.
EXPLICIT path: immutable once created, it decides which filters the signal may carry. technology catches adoption; hiring_role catches a role being hired; use_case_analysis has an AI read each posting against use_cases.
technology, hiring_role, use_case_analysis use_case_analysis only: how many postings per company the AI reads. Defaults to 10.
1 <= x <= 50Label for the signal, unique in the account. Optional on the described path (the drafter names it); required on the explicit path.
hiring_role only, at most 20. Referenced rather than copied, so editing a persona changes what the signal matches.
20use_case_analysis only, one to ten: the questions the AI answers over each posting.
10Show child attributes
Show child attributes
Response
OK
technology, hiring_role or use_case_analysis.
The kind, as List signals reports it and as a lead generation run takes it.
DESCRIBED path: the drafter's assumptions and anything it could not resolve. Read them: a signal drafted on a wrong assumption searches for the wrong thing quietly. Empty on the explicit path.
The use-case names the definition carries.
Always 0 on creation: a signal runs only when a lead generation program picks it.