curl --request POST \
--url https://api.tamtam.ai/api/v2/deal-stage-lookalike-signals \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"watched_stages": [
"<string>"
],
"countries": [
"<string>"
],
"exclude_existing_crm_companies": true,
"industries": [
"<string>"
],
"is_enabled": true,
"max_employees": 1,
"max_lookalikes_per_deal": 2,
"min_deal_amount": 1,
"min_employees": 1,
"min_score": 50,
"pipeline_ids": [
"<string>"
],
"sizes": [
"<string>"
]
}
'import requests
url = "https://api.tamtam.ai/api/v2/deal-stage-lookalike-signals"
payload = {
"name": "<string>",
"watched_stages": ["<string>"],
"countries": ["<string>"],
"exclude_existing_crm_companies": True,
"industries": ["<string>"],
"is_enabled": True,
"max_employees": 1,
"max_lookalikes_per_deal": 2,
"min_deal_amount": 1,
"min_employees": 1,
"min_score": 50,
"pipeline_ids": ["<string>"],
"sizes": ["<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({
name: '<string>',
watched_stages: ['<string>'],
countries: ['<string>'],
exclude_existing_crm_companies: true,
industries: ['<string>'],
is_enabled: true,
max_employees: 1,
max_lookalikes_per_deal: 2,
min_deal_amount: 1,
min_employees: 1,
min_score: 50,
pipeline_ids: ['<string>'],
sizes: ['<string>']
})
};
fetch('https://api.tamtam.ai/api/v2/deal-stage-lookalike-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/deal-stage-lookalike-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([
'name' => '<string>',
'watched_stages' => [
'<string>'
],
'countries' => [
'<string>'
],
'exclude_existing_crm_companies' => true,
'industries' => [
'<string>'
],
'is_enabled' => true,
'max_employees' => 1,
'max_lookalikes_per_deal' => 2,
'min_deal_amount' => 1,
'min_employees' => 1,
'min_score' => 50,
'pipeline_ids' => [
'<string>'
],
'sizes' => [
'<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/deal-stage-lookalike-signals"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"watched_stages\": [\n \"<string>\"\n ],\n \"countries\": [\n \"<string>\"\n ],\n \"exclude_existing_crm_companies\": true,\n \"industries\": [\n \"<string>\"\n ],\n \"is_enabled\": true,\n \"max_employees\": 1,\n \"max_lookalikes_per_deal\": 2,\n \"min_deal_amount\": 1,\n \"min_employees\": 1,\n \"min_score\": 50,\n \"pipeline_ids\": [\n \"<string>\"\n ],\n \"sizes\": [\n \"<string>\"\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/deal-stage-lookalike-signals")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"watched_stages\": [\n \"<string>\"\n ],\n \"countries\": [\n \"<string>\"\n ],\n \"exclude_existing_crm_companies\": true,\n \"industries\": [\n \"<string>\"\n ],\n \"is_enabled\": true,\n \"max_employees\": 1,\n \"max_lookalikes_per_deal\": 2,\n \"min_deal_amount\": 1,\n \"min_employees\": 1,\n \"min_score\": 50,\n \"pipeline_ids\": [\n \"<string>\"\n ],\n \"sizes\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tamtam.ai/api/v2/deal-stage-lookalike-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 \"name\": \"<string>\",\n \"watched_stages\": [\n \"<string>\"\n ],\n \"countries\": [\n \"<string>\"\n ],\n \"exclude_existing_crm_companies\": true,\n \"industries\": [\n \"<string>\"\n ],\n \"is_enabled\": true,\n \"max_employees\": 1,\n \"max_lookalikes_per_deal\": 2,\n \"min_deal_amount\": 1,\n \"min_employees\": 1,\n \"min_score\": 50,\n \"pipeline_ids\": [\n \"<string>\"\n ],\n \"sizes\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"is_enabled": true,
"kind": "<string>",
"name": "<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 deal stage lookalike signal
When a CRM deal reaches a stage you watch (a win, typically), the companies that most resemble that deal’s company are routed to the owning rep as company leads: each closed-won deal becomes a small prospecting list automatically.
Read List CRM deal stages first and pass its ids as watched_stages; a label typed by hand is not a valid value on HubSpot. Shape the candidates with countries, industries, sizes and the employee range: the signal fires on one deal and has no distribution of its own to learn a range from. exclude_existing_crm_companies defaults to true; recommending a company you already sold to is the most embarrassing thing this signal can do.
Needs a connected CRM. Only deals reaching the stage after creation count, so it stays quiet until the next one lands.
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/deal-stage-lookalike-signals \
--header 'Authorization: <api-key>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "<string>",
"watched_stages": [
"<string>"
],
"countries": [
"<string>"
],
"exclude_existing_crm_companies": true,
"industries": [
"<string>"
],
"is_enabled": true,
"max_employees": 1,
"max_lookalikes_per_deal": 2,
"min_deal_amount": 1,
"min_employees": 1,
"min_score": 50,
"pipeline_ids": [
"<string>"
],
"sizes": [
"<string>"
]
}
'import requests
url = "https://api.tamtam.ai/api/v2/deal-stage-lookalike-signals"
payload = {
"name": "<string>",
"watched_stages": ["<string>"],
"countries": ["<string>"],
"exclude_existing_crm_companies": True,
"industries": ["<string>"],
"is_enabled": True,
"max_employees": 1,
"max_lookalikes_per_deal": 2,
"min_deal_amount": 1,
"min_employees": 1,
"min_score": 50,
"pipeline_ids": ["<string>"],
"sizes": ["<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({
name: '<string>',
watched_stages: ['<string>'],
countries: ['<string>'],
exclude_existing_crm_companies: true,
industries: ['<string>'],
is_enabled: true,
max_employees: 1,
max_lookalikes_per_deal: 2,
min_deal_amount: 1,
min_employees: 1,
min_score: 50,
pipeline_ids: ['<string>'],
sizes: ['<string>']
})
};
fetch('https://api.tamtam.ai/api/v2/deal-stage-lookalike-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/deal-stage-lookalike-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([
'name' => '<string>',
'watched_stages' => [
'<string>'
],
'countries' => [
'<string>'
],
'exclude_existing_crm_companies' => true,
'industries' => [
'<string>'
],
'is_enabled' => true,
'max_employees' => 1,
'max_lookalikes_per_deal' => 2,
'min_deal_amount' => 1,
'min_employees' => 1,
'min_score' => 50,
'pipeline_ids' => [
'<string>'
],
'sizes' => [
'<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/deal-stage-lookalike-signals"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"watched_stages\": [\n \"<string>\"\n ],\n \"countries\": [\n \"<string>\"\n ],\n \"exclude_existing_crm_companies\": true,\n \"industries\": [\n \"<string>\"\n ],\n \"is_enabled\": true,\n \"max_employees\": 1,\n \"max_lookalikes_per_deal\": 2,\n \"min_deal_amount\": 1,\n \"min_employees\": 1,\n \"min_score\": 50,\n \"pipeline_ids\": [\n \"<string>\"\n ],\n \"sizes\": [\n \"<string>\"\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/deal-stage-lookalike-signals")
.header("Authorization", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"<string>\",\n \"watched_stages\": [\n \"<string>\"\n ],\n \"countries\": [\n \"<string>\"\n ],\n \"exclude_existing_crm_companies\": true,\n \"industries\": [\n \"<string>\"\n ],\n \"is_enabled\": true,\n \"max_employees\": 1,\n \"max_lookalikes_per_deal\": 2,\n \"min_deal_amount\": 1,\n \"min_employees\": 1,\n \"min_score\": 50,\n \"pipeline_ids\": [\n \"<string>\"\n ],\n \"sizes\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.tamtam.ai/api/v2/deal-stage-lookalike-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 \"name\": \"<string>\",\n \"watched_stages\": [\n \"<string>\"\n ],\n \"countries\": [\n \"<string>\"\n ],\n \"exclude_existing_crm_companies\": true,\n \"industries\": [\n \"<string>\"\n ],\n \"is_enabled\": true,\n \"max_employees\": 1,\n \"max_lookalikes_per_deal\": 2,\n \"min_deal_amount\": 1,\n \"min_employees\": 1,\n \"min_score\": 50,\n \"pipeline_ids\": [\n \"<string>\"\n ],\n \"sizes\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"is_enabled": true,
"kind": "<string>",
"name": "<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
Your connected CRM. Must match the crm passed to List CRM deal stages.
hubspot, salesforce Short label, unique in the account, e.g. 'Lookalikes of closed-won'.
1Stage ids from List CRM deal stages, never labels typed by hand.
1Two-letter country codes the candidates must be in.
Drop candidates you already have a deal on. Defaults to true; leave it on unless you want existing customers back.
Industry names the candidates must be in.
Defaults to true.
Largest candidate headcount. Omit for no ceiling.
x >= 0How many companies each won deal produces. Defaults to 25.
x >= 1Only deals worth at least this trigger the signal. Omit for every deal whatever its size.
x >= 0Smallest candidate headcount. Omit for no floor.
x >= 0Lookalike score floor, 0 to 100. Defaults to 70. Raise it for fewer, closer matches.
0 <= x <= 100HubSpot only: restrict to these pipelines. Salesforce cannot filter on pipeline.
LinkedIn employee-size buckets the candidates must fall in: 1-10, 11-50, 51-200, 201-500, 501-1000, 1001-5000, 5001-10000, 10001+.