CitationBenchTalk to Sales
API referenceLink Building

Inbound link-building API — autonomous negotiator for link requests

An autonomous negotiator that handles inbound link-building emails on your behalf. Drafts (and optionally sends) replies to negotiate swaps, paid placements, guest posts, and insertions — with eval gates that escalate to a human.

The inverse of outreach: an autonomous negotiator that handles inbound link-building requests on your behalf. Watches your connected inbox, drafts (and optionally sends) responses to negotiate link swaps, paid placements, guest posts, and link insertions. You configure eval gates — conditions that escalate to a human (e.g., partner asks for money, sender DR is below threshold, message looks like spam).

Conceptual overview

Every inbound link-building email becomes an InboundMessage. The agent (using the inbound_negotiator skill) decides what to do:

new email lands

InboundMessage created

classified (intent, sender DR, target page, prior history with partner)

eval gates checked

either: drafts reply autonomously     OR    escalates → WAITING_APPROVAL
    ↓                                       ↓
sent + LinkBuildingEvent logged      human reviews + decides

Three layers of control:

LayerWhat it controls
Workspace settingsMaster switch (on/off), default tone, default targeting angles you'll consider, default escalation thresholds
Per-account settingsPer partner: "auto-respond OK", "always escalate", "decline by default"
Eval gatesConditional rules — if message mentions $X+, escalate; if senderDR < 25, decline; if requestedAt > 3am, hold

Per-partner history is preserved on LinkBuildingRelationship — every inbound + every outbound reply shows up on the relationship timeline, so the next inbound has full context.

→ Concept: Link Building → Concept: Eval Gates → Concept: Approval Workflows

Endpoints

MethodPathPurpose
GET/v1/link-building/inboundList inbound messages
GET/v1/link-building/inbound/{id}Get one inbound message + draft state
POST/v1/link-building/inbound/ingestIngest a message (Gmail/Outlook webhook target)
POST/v1/link-building/inbound/{id}/draftRe-draft a response
POST/v1/link-building/inbound/{id}/approveApprove and send draft
POST/v1/link-building/inbound/{id}/rejectReject (decline, mark spam, archive)
GET/v1/link-building/inbound/pendingList inbound items waiting for manual action
GET/v1/link-building/inbound/historyFull message history with a partner
CRUD/v1/link-building/inbound/settingsWorkspace-level inbound behavior
CRUD/v1/link-building/inbound/account-settings/{accountId}Per-partner overrides
CRUD/v1/link-building/inbound/eval-gate/{...}Eval gate definitions

curl -G .../v1/link-building/inbound \
  --data-urlencode "status=DRAFT_READY,PENDING_REVIEW" \
  --data-urlencode "since=2026-05-20T00:00:00Z" \
  --data-urlencode "limit=50"
{
  "data": [
    {
      "id": "msg_***",
      "subject": "Quick request — guest post on Acme blog",
      "fromEmail": "alex@partnermag.com",
      "fromDomain": "partnermag.com",
      "senderDR": 38,
      "classification": "guest_post_pitch",
      "status": "DRAFT_READY",
      "linkedRelationshipId": "rel_***",
      "linkedAccountId": "acct_***",
      "receivedAt": "2026-05-23T11:32:00Z",
      "escalatedReason": null
    },
    {
      "id": "msg_***",
      "subject": "Re: paid link insertion offer",
      "fromEmail": "...",
      "classification": "paid_link_insertion",
      "status": "PENDING_REVIEW",
      "escalatedReason": "Eval gate matched: payment_request_escalation"
    }
  ],
  "total": 12
}
ParamNotes
statusNEW, DRAFT_READY, SENT, PENDING_REVIEW, DECLINED, MARKED_SPAM
classificationguest_post_pitch, link_swap, link_insertion, paid_link_insertion, partnership, update_link, other
escalatedOnlytrue to filter to inbound that's waiting for review
accountIdAll messages from one partner

curl .../v1/link-building/inbound/msg_***
{
  "id": "msg_***",
  "subject": "Quick request — guest post on Acme blog",
  "fromEmail": "alex@partnermag.com",
  "fromName": "Alex Partner",
  "fromDomain": "partnermag.com",
  "senderDR": 38,
  "originalBody": "Hi team,\n\nLove your blog. I'd love to contribute a guest post on ...",
  "receivedAt": "2026-05-23T11:32:00Z",
  "classification": "guest_post_pitch",
  "classificationConfidence": 0.91,
  "linkedRelationshipId": "rel_***",
  "linkedAccountId": "acct_***",
  "status": "DRAFT_READY",
  "draft": {
    "subject": "Thanks for reaching out — guest post specifics",
    "body": "Hi Alex,\n\nThanks for the kind words. We're open to contributors ...",
    "draftedBy": "agent",
    "agentId": "agt_***",
    "invocationId": "inv_***",
    "draftedAt": "2026-05-23T11:34:00Z",
    "tone": "friendly",
    "anglesConsidered": ["guest_post", "link_insertion"]
  },
  "evalGatesEvaluated": [
    { "gateId": "payment_request_escalation", "matched": false },
    { "gateId": "low_dr_decline", "matched": false }
  ],
  "prevExchanges": 0
}

POST /v1/link-building/inbound/ingest

Webhook target for Gmail / Outlook integrations. Most users set this up once and never call it directly.

curl -X POST .../v1/link-building/inbound/ingest \
  -H "Content-Type: application/json" \
  -d '{
    "source":    "gmail",
    "messageId": "<gmail-message-id>",
    "from":      { "email": "alex@partnermag.com", "name": "Alex Partner" },
    "to":        ["seo@acme.com"],
    "subject":   "Quick request — guest post on Acme blog",
    "body":      "Hi team, ...",
    "receivedAt":"2026-05-23T11:32:00Z"
  }'

CitationBench classifies, runs eval gates, drafts a response (if gates pass), and returns the new InboundMessage.


POST /v1/link-building/inbound/{id}/draft

Re-draft the response (e.g., after editing the targeting angle or the tone).

curl -X POST .../v1/link-building/inbound/msg_***/draft -d '{
  "tone":      "firm",
  "angle":     "link_insertion",
  "customInstructions": "Decline guest post but offer a paid link-insertion alternative."
}'

Returns the new draft (overwrites the previous).


POST /v1/link-building/inbound/{id}/approve

curl -X POST .../v1/link-building/inbound/msg_***/approve -d '{
  "edits": {
    "body": "Hi Alex, thanks — yes, here's our methodology PDF ..."
  },
  "scheduleAt": "2026-05-24T09:00:00-04:00"
}'

Sends the (optionally edited) draft. Creates a LinkBuildingEvent. Status moves to SENT.


POST /v1/link-building/inbound/{id}/reject

curl -X POST .../v1/link-building/inbound/msg_***/reject -d '{
  "action": "decline",
  "reason": "Off-topic",
  "markRelationship": "NOT_INTERESTED"
}'

action values:

  • decline — send a polite decline (templated)
  • mark_spam — move to spam, no response
  • archive_silent — archive without responding
  • block_sender — add sender to workspace blocklist

curl .../v1/link-building/inbound/pending

The action queue for humans. Same shape as the list endpoint, filtered to PENDING_REVIEW and grouped by why they were escalated.

{
  "byReason": {
    "payment_request": [
      {
        "id": "msg_***",
        "subject": "Re: paid link insertion offer",
        "fromEmail": "..."
      }
    ],
    "low_sender_dr": [],
    "suspicious_content": [
      { "id": "msg_***", "subject": "...", "fromEmail": "..." }
    ],
    "first_contact_with_high_value_account": [{ "id": "msg_***", "...": "..." }]
  },
  "total": 7
}

Full message history with one partner (across both inbound and outbound).

curl -G .../v1/link-building/inbound/history \
  --data-urlencode "accountId=acct_***"

Returns the merged event timeline (inbound messages + outbound emails + status changes).


curl .../v1/link-building/inbound/settings
{
  "enabled": true,
  "connectedInbox": {
    "type": "gmail",
    "address": "seo@acme.com",
    "connectedAt": "..."
  },
  "defaultTone": "friendly",
  "defaultAnglesYouConsider": ["guest_post", "link_insertion", "link_swap"],
  "autoSendIfAllGatesPass": false,
  "responseTimeoutDays": 7
}
curl -X PATCH .../v1/link-building/inbound/settings -d '{
  "autoSendIfAllGatesPass": true,
  "defaultTone": "firm"
}'

Per-partner overrides.

curl -X PUT .../v1/link-building/inbound/account-settings/acct_*** -d '{
  "mode":         "always_escalate",
  "customNotes":  "Long-time partner; double-check anything beyond a friendly reply"
}'

mode values:

  • inherit (default) — use workspace settings + eval gates
  • auto_respond — always auto-respond, skip eval gates
  • always_escalate — always require human review
  • auto_decline — automatic polite decline
  • block — auto-spam every inbound from this account

See Eval Gates concept for the rule language. CRUD operations:

curl    .../v1/link-building/inbound/eval-gate         # list
curl -X POST .../v1/link-building/inbound/eval-gate    # create
curl -X PATCH .../v1/link-building/inbound/eval-gate/gate_***
curl -X DELETE .../v1/link-building/inbound/eval-gate/gate_***
curl -X POST .../v1/link-building/inbound/eval-gate/gate_***/test  # test against historical inbound

MCP

> What inbound link-building messages need my review?

Claude calls link_building.inbound.pending.

> Show the message from alex@partnermag.com.

Claude calls link_building.inbound.list + link_building.inbound.get.

> Approve and send the draft. Add a quick note that I'll send the methodology PDF.

Claude calls link_building.inbound.approve with edits.

> Always escalate inbound from engineering-blog.com — they're a high-value partner.

Claude calls link_building.inbound.account_settings.update.


Errors

StatusCodeCause
404inbound_message_not_found
422already_respondedTrying to draft/approve a message that's already been sent
422eval_gate_blocksA gate forbids auto-send
503inbox_unavailableGmail / Outlook connection failed

Cost

ActionCredits
Per inbound classified0.5
Per draft3
Per re-draft3
Approve + send2 (the send)
Reject (decline send)1
GETsfree

Use cases (string things together)

A. Set up the autonomous responder

# 1. Connect Gmail
curl -X POST .../v1/link-building/inbound/settings -d '{ "enabled": true, "connectedInbox": { "type": "gmail" } }'
# (OAuth flow ...)

# 2. Set up two essential eval gates
curl -X POST .../v1/link-building/inbound/eval-gate -d '{
  "name": "payment_request",
  "when": { "llm_check": "Is the sender asking for money?" },
  "then": { "action": "escalate_to_approval" }
}'
curl -X POST .../v1/link-building/inbound/eval-gate -d '{
  "name": "low_dr_decline",
  "when": { "field_lt": { "senderDR": 20 } },
  "then": { "action": "decline" }
}'

# 3. Enable auto-send when all gates pass
curl -X PATCH .../v1/link-building/inbound/settings -d '{ "autoSendIfAllGatesPass": true }'

B. Daily approval queue

curl .../v1/link-building/inbound/pending | jq '.byReason'

Pipe to your portal or Slack.

C. Bulk-mark partners

for ACCT in acct_A acct_B acct_C; do
  curl -X PUT .../v1/link-building/inbound/account-settings/$ACCT -d '{ "mode": "always_escalate" }'
done

D. Audit what the agent declined last month

curl -G .../v1/link-building/inbound \
  --data-urlencode "status=DECLINED" \
  --data-urlencode "since=$(date -u -d '30 days ago' -Iseconds)"

On this page