mySDRDocs

API reference

List the Leads table

The Leads table as the user sees it in mySDR: the leads from the signals on Signals, plus the people an agent saved. total is the number next to the Leads tab when no filter is set. Each row says where it came from, which signals found it and where its outreach stands. The Leads and Companies tables are what the user sees in mySDR. Your agent decides what goes in them: search results do not land there by themselves. The user keeps the overview there; your agent reads the same tables here and fills them with POST.

GEThttps://mysdr.app/api/v1/tables/leads
View Markdown

A person who is both a signal lead and saved by an agent is one row (the signal lead), with the state the agent set on it: its next action, address, fields and campaigns, and needs_decision while Leads says new. saved_ids gives the id of the agent's own row. table counts the whole table, whatever the filter: by source and, when it can be read, by outreach state. capped is true when there are more than 5,000 signal leads; the numbers are then a lower bound.

Authentication

Send Authorization: Bearer gtk_…. Create the key under Connect assistant → API keys. Every gtk_ key can call these routes, also while the Signals API is closed. A missing, invalid or revoked key is 401.

Query parameters

  • q string — Only rows whose name, title, company, place, signal or one of your own field values contains this text (up to 100 characters).
  • source string — Only rows from the signals on Signals, or only what an agent saved. One of: signal, assistant.
  • limit integer — How many rows to return, from 1 to 100. Defaults to 50.
  • offset integer — Skip this many rows. Pass next_offset of the previous page.
  • outreach string — Only rows in this outreach state; any = with outreach, none = without. One of: scheduled, ongoing, replied, done, any, none.
  • lifecycle string — Only rows in this state of the Status column the user sees (lifecycle on each row); open = new, scheduled, contacted, replied, interested and meeting. Several separated by commas. One of: new, scheduled, contacted, replied, interested, meeting, later, no_reply, not_interested, archived, open.
  • status string — Only rows with this status; several separated by commas. A snooze that ended counts as new. One of: new, needs_decision, snoozed, archived.
  • lead_status string — Only rows with this lead status; none = without one. Several separated by commas. One of: interested, meeting, later, not_interested, none.
  • due string — By next action: today (today and everything overdue), overdue, week (the next 7 days and overdue), any (has one), none. One of: today, overdue, week, any, none.
  • campaign string — Only rows in this campaign (a campaign id).
  • stage string — Only rows in these stages (keys from GET /stages); none = without a stage. Several separated by commas.
  • owner string — Only rows of these owners: me, a colleague's email address or user id (GET /team), or none. Several separated by commas.
  • do_not_contact boolean — true = only rows on the exclusions (marked Do not contact in mySDR), false = only rows that may be contacted.
  • agent_signal string — Only rows your own signals caught (POST /agent-signals/{key}/hits): their keys, separated by commas. A key the organization does not have is a 400.
  • field.{key} string — Only rows whose own field {key} has this value; several separated by commas (any of them). Text without case, a number by its value, true/false or yes/no for a yes/no field. E.g. field.ats=recruitee,teamtailor.
  • field.{key}.gte number — Only rows whose field {key} is a number of at least this. E.g. field.fte.gte=200.
  • field.{key}.lte number — Only rows whose field {key} is a number of at most this.
  • field.{key}.exists boolean — true = the field has a value, false = it has none. Up to 10 field filters, all must match.

Response

  • object string · required — Always list. One of: list.
  • total integer · required — Rows that match this request. Without a filter: the number next to the Leads tab.
  • data object[] · required — Rows, newest first. id (a signal lead: its number in mySDR; a saved person: the sav_… or per_… that PATCH and DELETE take), source (signal or assistant), name, title, headline, company, company_linkedin_url, company_domain, location, country_code, linkedin_url, signals (the names in the Signals column, your own signals included), agent_signals (your own signals that caught it, newest first: key, name, first_at, last_at, summary (what you last saw) and source_url; empty = none), note, added_at, last_signal_at, outreach (status, label, attention, last_activity_at, next_step_at, campaign_ids, or null), lifecycle (the Status column the user sees, derived from status, lead_status and outreach, read-only; the first that fits: archived, not_interested, meeting, interested, later (they said later, or a snooze), replied, no_reply (outreach done without a reply), contacted, scheduled, else new), the state (status, status_reason, snooze_until, lead_status, next_action (at, kind, note, email when you planned one, without its text in a list, or null), out_of_office_until, fields, campaign_ids, stage (a stage key, or null) and owner (id, name, email, or null), plus email and email_status), saved_ids (the ids of the agent's own row: PATCH takes them; empty for a signal lead nobody saved), do_not_contact (the exclusions on this person, by their address or their employer's domain or name, each with type, reason and message; empty = may be contacted; a bounced address only blocks email and is not listed) and dashboard_url.
  • next_offset integer | null · required — The offset of the next page, or null.
  • table object · required — leads, from_signals, from_assistant, outreach (a count per state, or null), lifecycle (a count per state of the Status column), status (a count per status), due_today (rows whose next action is today or overdue), do_not_contact (rows on the exclusions) and capped.
  • dashboard_url string · required — The Leads table in mySDR.

Credits

Free. This call never uses credits.

Errors

  • 400 invalid_request — An unknown source, outreach, lifecycle, status, lead_status or due, a campaign that is not an id, a stage that is not a key, an owner who is not in the organization, an agent_signal the organization does not have, a field filter that is not valid (param names it), a do_not_contact that is not true or false, a limit outside 1 to 100, or a negative offset.
  • 401 authentication_error — The Authorization header is missing, or the key is unknown or revoked.
  • 403 permission_error — API access is not part of your plan, or your account is suspended.
  • 429 rate_limit_error — More than 60 requests per minute, or more than 3 at the same time, on one key. Wait for the Retry-After header.
  • 503 service_unavailable — The API is temporarily unavailable. Retry later.
  • 500 internal_error — Something went wrong on our side.

Example

cURL

curl "https://mysdr.app/api/v1/tables/leads?limit=25" \
  -H "Authorization: Bearer $MYSDR_API_KEY"

JavaScript

const response = await fetch('https://mysdr.app/api/v1/tables/leads?limit=25', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${process.env.MYSDR_API_KEY}`
  }
});
const body = await response.json();

Python

import json
import os
import urllib.request

request = urllib.request.Request(
    "https://mysdr.app/api/v1/tables/leads?limit=25",
    headers={
    "Authorization": f"Bearer {os.environ['MYSDR_API_KEY']}"
    },
    method="GET",
)
with urllib.request.urlopen(request) as response:
    body = json.load(response)

Example response

{
  "object": "list",
  "total": 2,
  "data": [
    {
      "id": "sav_7c1f2a40-5b0e-4c3e-9a71-2f7d3e0c9b11",
      "object": "table_lead",
      "source": "assistant",
      "name": "Jane Example",
      "title": "CFO",
      "company": "Acme Analytics",
      "country_code": "BE",
      "linkedin_url": "https://www.linkedin.com/in/jane-example",
      "signals": [
        "Companies that raised funding · BE"
      ],
      "note": "CFO at a company that raised a Series A last week.",
      "added_at": "2026-10-23T09:30:00.000Z",
      "outreach": null,
      "lifecycle": "new"
    },
    {
      "id": "48213",
      "object": "table_lead",
      "source": "signal",
      "name": "Tom Sample",
      "title": "Head of Finance",
      "company": "Beta Labs",
      "country_code": "NL",
      "signals": [
        "New finance leaders · Benelux"
      ],
      "added_at": "2026-10-21T07:12:00.000Z",
      "outreach": {
        "status": "ongoing",
        "label": "Invite sent",
        "attention": null,
        "last_activity_at": "2026-10-22T10:00:00.000Z",
        "next_step_at": "2026-10-24T09:00:00.000Z",
        "campaign_ids": []
      },
      "lifecycle": "contacted"
    }
  ],
  "next_offset": null,
  "table": {
    "leads": 2,
    "from_signals": 1,
    "from_assistant": 1,
    "outreach": {
      "scheduled": 0,
      "ongoing": 1,
      "replied": 0,
      "done": 0
    },
    "capped": false
  },
  "dashboard_url": "https://mysdr.app/en/gtm/leads"
}