Companies
Company records with firmographics, pipeline rollups and attribution, whether or not a CRM is connected.
| Endpoint | Method | Path | Permission |
|---|---|---|---|
| List companies Companies, with firmographics, pipeline rollups and attribution | GET | /v1/companies | companies:read |
| Get company One company, with its deals and its people | GET | /v1/companies/{id} | companies:read |
| Update company Correct a company's firmographics | PATCH | /v1/companies/{id} | companies:write |
| Get company journey The account journey: everyone at the company, merged | GET | /v1/companies/{id}/journey | companies:read |
Base URL https://app.sourceloop.ai/api/v1
List companies
Companies, with firmographics, pipeline rollups and attribution
GET /v1/companies
Requires companies:read
Unlike deals, this does NOT require a CRM. A company record comes either from a connected CRM or from our own domain resolution off a captured lead email, and `source` on each row says which. So this answers "which companies are on my site" even with no CRM at all.
Personal email domains (gmail and similar) are excluded by default: they are one person, not a company. Pass include_personal=true to keep them.
curl -s -X GET "https://app.sourceloop.ai/api/v1/companies?website=acme.com" \
-H "Authorization: Bearer $SOURCELOOP_API_KEY" const res = await fetch(
"https://app.sourceloop.ai/api/v1/companies?website=acme.com",
{
method: "GET",
headers: {
Authorization: `Bearer ${process.env.SOURCELOOP_API_KEY}`,
},
},
);
const data = await res.json(); import os, requests
res = requests.get(
"https://app.sourceloop.ai/api/v1/companies?website=acme.com",
headers={"Authorization": f"Bearer {os.environ['SOURCELOOP_API_KEY']}"},
)
data = res.json() Query parameters
websitestringWebsite domain, e.g. acme.com. Required only when the key covers more than one.
domainstringindustrystringcountrystringlifecycle_stagestringhas_dealsbooleanhas_open_dealsbooleanchannelstringFirst-touch channel.
include_personalbooleanDefault
falsesortstringAllowed values 4
last_seenpipelinewonconversions
cursorstringlimitintegerDefault
50total_countbooleanInclude meta.total_count, the exact number of matching rows. Off by default because counting scans every match while the page itself reads one page, so on a large workspace the count costs far more than the rows. Paginate with has_more and next_cursor unless you are rendering "70 of 366".
Default
false
Responses
-
200Companies -
429Too many requests for this workspace in the current minute. Wait Retry-After seconds and repeat the request unchanged.
Get company
One company, with its deals and its people
GET /v1/companies/{id}
Requires companies:read
The account-based view: firmographics, pipeline rollups, attribution, every deal attached to the company, and the people from it aggregated so the same person is not counted twice.
curl -s -X GET "https://app.sourceloop.ai/api/v1/companies/{id}" \
-H "Authorization: Bearer $SOURCELOOP_API_KEY" const res = await fetch(
"https://app.sourceloop.ai/api/v1/companies/{id}",
{
method: "GET",
headers: {
Authorization: `Bearer ${process.env.SOURCELOOP_API_KEY}`,
},
},
);
const data = await res.json(); import os, requests
res = requests.get(
"https://app.sourceloop.ai/api/v1/companies/{id}",
headers={"Authorization": f"Bearer {os.environ['SOURCELOOP_API_KEY']}"},
)
data = res.json() Path parameters
idstringpathrequired
Responses
-
200Company detail -
404Something was wrong with the request or the credential. -
429Too many requests for this workspace in the current minute. Wait Retry-After seconds and repeat the request unchanged.
Update company
Correct a company's firmographics
PATCH /v1/companies/{id}
Requires companies:write
Most companies here were discovered from traffic and identity stitching rather than imported from a CRM, so nobody else owns them and this is a plain local write. When a company IS linked to a CRM connection the write still lands and the response carries a `warning` saying the next sync will overwrite it.
Engagement counts, deal rollups and every first_*/latest_* attribution column are computed by Sourceloop and are refused rather than ignored.
curl -s -X PATCH "https://app.sourceloop.ai/api/v1/companies/{id}" \
-H "Authorization: Bearer $SOURCELOOP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"industry": "Logistics",
"employee_count": 240
}' const res = await fetch(
"https://app.sourceloop.ai/api/v1/companies/{id}",
{
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.SOURCELOOP_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"industry": "Logistics",
"employee_count": 240
}),
},
);
const data = await res.json(); import os, requests
res = requests.patch(
"https://app.sourceloop.ai/api/v1/companies/{id}",
headers={"Authorization": f"Bearer {os.environ['SOURCELOOP_API_KEY']}"},
json={
"industry": "Logistics",
"employee_count": 240
},
)
data = res.json() Path parameters
idstringpathrequired
Headers
Idempotency-Keystringheader
Request body
company_namestringindustrystringsize_rangestringemployee_countintegerannual_revenuenumbercountrystringregionstringcitystringwebsite_urlstringdescriptionstringlinkedin_urlstring
Responses
-
200Updated, or unchanged -
403Something was wrong with the request or the credential. -
404Something was wrong with the request or the credential. -
429Too many requests for this workspace in the current minute. Wait Retry-After seconds and repeat the request unchanged.
Get company journey
The account journey: everyone at the company, merged
GET /v1/companies/{id}/journey
Requires companies:read
Every session by every person at the company, ordered across all of them, because in B2B the person who first read a blog post is rarely the person who signs. people_count reports how many were merged.
curl -s -X GET "https://app.sourceloop.ai/api/v1/companies/{id}/journey?days=365" \
-H "Authorization: Bearer $SOURCELOOP_API_KEY" const res = await fetch(
"https://app.sourceloop.ai/api/v1/companies/{id}/journey?days=365",
{
method: "GET",
headers: {
Authorization: `Bearer ${process.env.SOURCELOOP_API_KEY}`,
},
},
);
const data = await res.json(); import os, requests
res = requests.get(
"https://app.sourceloop.ai/api/v1/companies/{id}/journey?days=365",
headers={"Authorization": f"Bearer {os.environ['SOURCELOOP_API_KEY']}"},
)
data = res.json() Path parameters
idstringpathrequired
Query parameters
daysintegerDefault
365
Responses
-
200Journey -
404Something was wrong with the request or the credential. -
429Too many requests for this workspace in the current minute. Wait Retry-After seconds and repeat the request unchanged.