Skip to content New SourceLoop MCP: chat with your attribution data in Claude, ChatGPT & Cursor
SourceLoop
API reference

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

websitestring

Website domain, e.g. acme.com. Required only when the key covers more than one.

domainstring

industrystring

countrystring

lifecycle_stagestring

has_dealsboolean

has_open_dealsboolean

channelstring

First-touch channel.

include_personalboolean

Default false

sortstring

Allowed values 4

  • last_seen
  • pipeline
  • won
  • conversions

cursorstring

limitinteger

Default 50

total_countboolean

Include 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

  • 200 Companies
  • 429 Too 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

  • 200 Company detail
  • 404 Something was wrong with the request or the credential.
  • 429 Too 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_namestring

industrystring

size_rangestring

employee_countinteger

annual_revenuenumber

countrystring

regionstring

citystring

website_urlstring

descriptionstring

linkedin_urlstring

Responses

  • 200 Updated, or unchanged
  • 403 Something was wrong with the request or the credential.
  • 404 Something was wrong with the request or the credential.
  • 429 Too 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

daysinteger

Default 365

Responses

  • 200 Journey
  • 404 Something was wrong with the request or the credential.
  • 429 Too many requests for this workspace in the current minute. Wait Retry-After seconds and repeat the request unchanged.

Track every conversion to its true source

Capture and send full attribution data from every signup, lead, booking, and sale to your CRM and ad platforms, so you know exactly what's driving revenue.

Without SourceLoop

Untagged

Kayden Floyd

kayden@abc.com

  • SourceUnknown
  • MediumUnknown
  • CampaignUnknown
  • Landing pageUnknown
Journey
No touchpoints captured

With SourceLoop

Auto-tagged

Kayden Floyd

kayden@abc.com · Acme Co.

  • Channel Paid Social
  • CampaignFree_demo
  • Landing page/pricing
Journey
Synced to HubSpot Google Ads Meta