> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentlinkops.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Run outreach from your own email

> Save publisher pages as prospects, send pitches from your own mailbox through your agent, record each outcome, and let a link check confirm the win.

Your agent finds the publisher page and drafts the pitch. You send it from your own mailbox. AgentLinkOps keeps the prospect, the outcome you report and every check of the page, and marks the prospect won only when a check finds your link.

AgentLinkOps never sends email. You don't need a sequencer for this guide.

## What you end up with

One prospect, as it reads in AgentLinkOps over a campaign:

| When | `outreachStatus` | `lastContactedAt` | Set by |
| - | - | - | - |
| You save the page | `candidate` | empty | AgentLinkOps default |
| Your pitch leaves your mailbox | `requested` | `2026-10-21` | Your agent |
| The editor replies "sounds good" | `pending` | `2026-10-21` | Your agent |
| A check finds your link on the page | `won` | `2026-10-21` | AgentLinkOps |

After the win, the prospect becomes an earned link. AgentLinkOps checks it daily and records a change if it disappears.

## Before you start

* An AgentLinkOps project for your site, with your agent [connected through MCP](/guides/connect-mcp).
* An agent with a mail connector for your mailbox, such as Gmail, Outlook or Zoho. It needs to create drafts and read your Sent folder.
* Optional: the free AgentLinkOps skills, which help your agent qualify publisher pages and draft pitches. Install them with `npx -y agentlinkops agent setup`.

Each prospect uses one check when you add it, then one check a week. Checks come from your workspace's shared monthly allowance; `get_workspace` shows what remains.

## 1. Save prospects

Give AgentLinkOps the exact publisher page where your link would go, plus the page on your site it should point to. Use the page, not the publisher's homepage. A check reads that one page.

Call [import\_link\_watches](/reference/commands/import_link_watches) with up to 100 rows:

```json theme={null}
{
  "projectId": "prj_example",
  "watches": [
    {
      "sourceUrl": "https://publisher.example/resources/seo-tools",
      "targetUrl": "https://your-site.example/",
      "targetScope": "domain",
      "intent": "prospect",
      "campaign": "Resource pages Q4",
      "localReference": "crm-1042"
    }
  ]
}
```

* `targetScope: "domain"` counts a link to any page on your site. Use `"exact"` when only one page counts.
* `localReference` is your own record id, up to 200 characters. Your agent joins its notes to AgentLinkOps on this value, never on URLs.
* `campaign` is your label, up to 80 characters.

Save each row's watch id (`rows[].watch.id` in the response). A row that matches an existing watch returns that watch and starts no new check. It does apply the intent, status and campaign you sent, so don't re-import a link you've already earned as a prospect.

## 2. Draft and send from your mailbox

Ask your agent to draft one pitch per prospect into your mailbox. You review each draft and send it yourself. A draft is not contact. Nothing changes in AgentLinkOps until the message is in your Sent folder.

Keep the editor's name and address in your mail tool or your own CRM. AgentLinkOps doesn't store contact email addresses today.

> **Optional: label who you contacted**
>
> To see a contact label next to the link, read the watch's current revision with [get\_link\_lifecycle](/reference/commands/get_link_lifecycle), then call [update\_link\_lifecycle](/reference/commands/update_link_lifecycle) with `deal.contactRef` (your id for the person) and `deal.contactLabel`, such as `"Editor, SEO tools page"`. The label rejects email addresses, URLs and phone numbers.

## 3. Record what happened

Once a day, your agent reads your Sent folder and replies and writes each outcome with [update\_link\_watch](/reference/commands/update_link_watch):

| What happened | Write |
| - | - |
| Your pitch or follow-up was sent | `outreachStatus: "requested"` and `lastContactedAt` set to the send date |
| The editor replied and the conversation is open | `"pending"` |
| The editor said no, or asked you to stop | `"declined"` |
| The address bounced, or you found no way to reach anyone | `"abandoned"` |
| You're done with a declined or abandoned prospect | Also `intent: "retired"`, which stops its weekly checks |
| The editor says the link is live | Nothing yet. Run the check in step 4 |
| The message was opened, or a link in it was clicked | Nothing |

Only a sent message moves `lastContactedAt`. Replies, opens and clicks never change it.

### Never move a status backwards

A daily read sees the same sent message and the same reply again. Before each write, your agent reads the watch and never lets a status go backwards:

* Never overwrite `won`, `declined` or `abandoned` from an automatic read. Change those only when you decide to.
* Move forward only: `candidate`, then `requested`, then `pending`.
* Only move `lastContactedAt` to a later date. A follow-up sent to a `pending` prospect keeps `pending` and still moves the date.

With this rule, running the same daily read twice changes nothing.

One call can update up to 100 watches that share the same status and date:

```json theme={null}
{
  "watchIds": ["wat_example_1", "wat_example_2"],
  "outreachStatus": "requested",
  "lastContactedAt": "2026-10-21"
}
```

Prospects sent on different days need one call per date. Recording an outcome never starts a check or sends anything.

## 4. Let a check confirm the link

When an editor says the link is up, request one check of that prospect with [request\_check](/reference/commands/request_check):

```json theme={null}
{
  "subject": "link",
  "subjectId": "wat_example_1",
  "idempotencyKey": "live-claim-wat_example_1-2026-10-21"
}
```

Use a new `idempotencyKey` for each new claim; reusing one returns the earlier job. Read [get\_check\_job](/reference/commands/get_check_job) until the job finishes, then read the watch with [get\_link\_watch](/reference/commands/get_link_watch).

* **Link found:** `outreachStatus` is `won` and `intent` is `earned`. A `prospect_won` event appears in [list\_events](/reference/commands/list_events) for the `links` feed.
* **Link not found, or the check couldn't finish:** the prospect stays a prospect. A blocked or incomplete check is unknown, so it proves nothing either way. Ask the editor for the exact page, or wait for the weekly check.

Don't write `won` yourself. An editor's reply or a tool's "success" flag is a claim. The check is the proof.

## 5. After the win

The earned link moves to daily checks. A link counts as lost only after two complete checks, at least 30 minutes apart, find it missing. [Monitor changes](/guides/monitor-changes) covers alerts and the change feed.

## Close out prospects you're done with

`declined` and `abandoned` record the outcome; they don't stop the weekly checks. To stop spending checks on a prospect, set `intent: "retired"` with `update_link_watch`. That pauses it and keeps its history.

To reopen it, set `intent: "prospect"` and `status: "active"`. Weekly checks resume; if a week has passed since its last check, one runs right away. To confirm sooner, use `request_check`.

## Fix a mistake

* **Wrong status:** write the right one with `update_link_watch`. A status you set by hand replaces the old one.
* **A request timed out:** list your prospects with `list_link_watches` and `q` set to your `localReference` before retrying. Retry a check with the same `idempotencyKey` so you get the same job, not a second check.
* **Added the same page twice:** when the source URL, target URL and `targetScope` all match, the import returns the existing watch and counts it under `existing`. A different `targetScope` creates a second watch; retire the one you don't want.

## Copy this into your agent

```text theme={null}
Use AgentLinkOps to track my outreach. Do not send anything I haven't approved.
1. Save each qualified publisher page with import_link_watches:
   intent "prospect", campaign "<my label>", localReference "<my CRM id>".
2. Draft one pitch per prospect in my mailbox. I review and send.
3. Read my Sent folder and replies daily. Update each watch with update_link_watch:
   sent -> requested plus lastContactedAt; open reply -> pending;
   no -> declined; bounce -> abandoned. Ignore opens and clicks.
   Read the watch first. Never overwrite won, declined or abandoned,
   never move a status backwards, but still move lastContactedAt to a
   later send date.
   When I close a declined or abandoned prospect, set intent retired.
4. When an editor says the link is live, call request_check for that watch,
   wait for the job, then read the watch. Never write won yourself.
5. Keep contact details in my mail and CRM, not in AgentLinkOps.
```

## Use a sequencer instead

If you want address finding and automatic follow-ups, add a sequencer. Steps 1, 4 and 5 stay the same.

* [Hunter](/guides/outreach-hunter): the one we recommend. It finds and verifies the editor's address, has a free plan and sends slowly from your own mailbox.
* [lemlist](/guides/outreach-lemlist): for teams already on lemlist, or agents that connect with OAuth.
* [Instantly](/guides/outreach-instantly): for people who already send cold email with Instantly.

Already keep outreach in a CRM? See [use your existing CRM and email sender](/guides/crm-sender-handoff).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.