Agent Native CRM

POST/v1/people

One conversation per person, across a campaign

There is no LinkedIn integration here and there will not be one. What there is: a person keyed on their profile URL, a linkedin channel that carries the draft, and a chain that turns a campaign into one readable thread per human being.

Who this is for

If this is not you, one of the other workflows probably is — they share every primitive and differ only in what the agents are pointed at.

The team

A founder or a go-to-market team whose first touch is a profile, not an inbox.

What they end up with

Everyone you approached, what was said, what came back, and who is not to be approached again.

The agents, and what each one is responsible for

These are your agents, not ours. This product ships no model and makes no decisions; it is the workspace they share and the record they leave. Each of them reaches it through the same API a person’s dashboard uses.

List-building agent

Upserts a person for every profile it finds and puts them on the campaign list.

Brings whatever it uses to find people. There is no profile search in this API.

Research agent

Claims a research task per person, writes what it found as a note, and qualifies or rejects the list member.

Brings its own reading of the profile, the site, and anything else public.

Messaging agent

Drafts the first message into a task, sends it, and chains the next one behind it.

Brings the account that actually sends. We have not got one.

Conversation agent

Records replies and platform events on the person's timeline, and stops the campaign when someone says no.

Brings the notifications it is watching.

The handoff, in the order it happens

Every call named here is one this API serves — a test reads them back against the operation table and fails on anything invented. What an agent does between two of them is its own business, and ours ends at the write.

Give the workspace a word for what happens on the platform

List-building agent

The activity vocabulary is editable, and a type has to exist before it can be used. Registering connection_accepted makes it a first-class entry you can filter the timeline by, rather than a note nobody can query.

  • GET /v1/schema
  • POST /v1/schema/activity-types
  • A connection_accepted activity type
  • schema_changed carrying the diff

Upsert a person for every profile, keyed on the profile URL

List-building agent

A person needs an email or a LinkedIn URL and one is enough. The URL is normalised before it is matched, so the same profile found by two agents on two days is one record with two sources on its timeline.

  • POST /v1/people
  • POST /v1/lists
  • POST /v1/lists/{id}/members
  • Person records keyed on linkedin_url
  • One list of people, all at candidate

Put the research on the queue, unassigned

List-building agent

A task with no assignee belongs to whoever claims it first. Run five research agents or one; the queue does not care, and neither of them can take the same person twice.

  • POST /v1/tasks
  • GET /v1/tasks
  • One research task per person, on the workspace queue

Claim it, read the profile, write down what you found

Research agent

A 409 already_claimed means another agent got there first: move to the next task, do not retry. What it learned goes on the timeline as a note with a source and a confidence — not into a field where the reasoning would be lost.

  • POST /v1/tasks/{id}/claim
  • POST /v1/activities
  • PATCH /v1/lists/{id}/members/{member_id}
  • POST /v1/tasks/{id}/complete
  • note activities carrying the research and its source
  • Member status qualified or rejected, with a reason
  • task_closed on the person

Draft the message into a task a person can read

Messaging agent

For a linkedin task the payload is to — the profile URL — and body. Delivery state does not go in there: the task's status and its completion outcome carry whether it was sent.

  • POST /v1/tasks
  • One linkedin task linked to the person
  • task_created

Check it sounds like you before it leaves

A human

The dashboard renders the chain as a conversation — first message, then each follow-up, with the current one marked. This is the point of the whole arrangement: the draft is reviewable because it is data, not a side effect.

  • PATCH /v1/tasks/{id}
  • POST /v1/tasks/{id}/claim
  • Nothing, unless you change it. Then field_changed says you did.

Send it with your own account, then chain what comes next

Messaging agent

Point each follow-up at the message immediately before it rather than at the first. The human gets one ordered thread, and every individual send stays separately claimable by whichever agent is free.

  • POST /v1/tasks/{id}/complete
  • POST /v1/tasks
  • task_closed with the outcome
  • The next linkedin task, chained on parent_task_id

Record what came back

Conversation agent

A reply, an accepted connection, a message that went nowhere. The type has to be one the workspace knows, which is what step one was for. Activities are never edited and never deleted, so the account of the conversation cannot be tidied up afterwards.

  • POST /v1/activities
  • GET /v1/activities
  • replied and connection_accepted on the person

Stop when you are asked to stop

Conversation agent

Set the person to do_not_contact with the words they used. Every later task on a channel that reaches them is refused by the API. This is enforcement, not a flag an agent is asked to check.

  • PATCH /v1/people/{id}
  • A do_not_contact activity carrying the reason
  • Every later contact task on that person refused with 409

Open a deal on the day it becomes one

Conversation agent

Most of these conversations are not deals and should not be. When one is, the person is already a record with a timeline behind it, so the deal starts with its own history rather than an empty note field.

  • POST /v1/deals
  • POST /v1/deals/{id}/stage
  • One deal at new, contacts already linked
  • stage_changed to contacted

GET/v1/activities

Everyone you approached, what was said, what came back, and who is not to be approached again.

Where a person steps in

None of these is a setting somebody has to switch on. Most are enforced by the API itself; the rest are enforced by the fact that the work sits in a queue until somebody takes it.

Before the first message

Social outreach fails on tone before it fails on targeting. The draft sits in a task until somebody claims it, so reading it is not a special mode — it is just the queue.

When the account is yours

Claim the task yourself and send it by hand. A human and an agent claim through the same route, and the timeline records which of you it was.

When two profiles are one person

An agent that suspects a duplicate writes a note naming the record it suspects. It does not merge — that is a judgement about the world, not about the data. You decide, and the note stays either way.

When someone says no

do_not_contact is a status with a reason, set on the record. Nothing about the campaign has to be reconfigured: every future contact task on that person is refused by the API itself.

GET/v1/schema

What the workspace looks like afterwards

Read it back and this is what is there. None of it was configured in a settings screen: every object, field, stage and activity type in this list was written through the API by an agent, and every change is on the timeline as schema_changed with the diff attached.

/v1/schema
person
Keyed on the LinkedIn URL, normalised before matching.
list
The campaign, with a status and a reason per member.
deal
Opened only for the conversations that become one.
activities
  • note
  • messaged
  • replied
  • task_created
  • task_closed
  • do_not_contact
  • connection_accepted

Highlighted types are ones this workflow registers before it uses them.

channels
  • research
  • linkedin

Out of the seven a task can carry.

pipeline
  • new
  • contacted
  • qualified
  • proposal
  • negotiation
  • won
  • lost

The pipeline every workspace starts with.

What this CRM does not do here

Said plainly, because each of these is a thing a CRM is usually expected to do, and an agent that assumes we do it will write code that never runs.

No LinkedIn integration

No login, no cookie, no session, no scraping, and none of their API behind ours. linkedin is the name of a task channel and the shape of its payload — a label on work, not a connection to a platform.

No sending and no listening

Your agent sends with its own account, under whatever that platform's rules allow, and writes the result back here. We never see the message leave and we never see the reply arrive.

No numbers arriving on their own

Follower counts, connection degrees, profile views: if one is on a record it is because an agent wrote it, with the source it wrote beside it.

The other workflows

Same primitives, pointed somewhere else. The differences worth reading are in the schema each one asks for and the moment a person is called in.

GET/v1/schema

Agentic CRM

The category these three are instances of: what an agentic CRM is, how it differs from the one you already run, and why the provenance on every write is the part that matters.

Read the argument

GET/skill.md

The contract itself

The file an agent reads before it writes anything. Every workflow on this site is assembled out of the calls it documents, and nothing else.

Read /skill.md

Point an agent at an empty workspace

An agent can create one with no key, no invitation and no human, and run this whole workflow through it before anybody decides whether it belongs here. Your API calls are never rate limited and agents are never counted.