CitationBenchTalk to Sales
API referenceLink Building

Competitor link outreach API — automate replacement-link campaigns from a competitor domain

Seed a campaign with a competitor domain. The agent pulls their backlinks via Ahrefs, filters for quality and relevance, discovers contacts, and drafts personalized outreach pitching your content as a parallel option.

Sibling endpoint to SERP outreach. Instead of a SERP, the seed is a competitor domain — CitationBench pulls every site linking to the competitor (via Ahrefs), filters for quality and relevance, discovers contacts, and drafts outreach pitching your content as a parallel/replacement option.

Same downstream model as SERP outreach: drafts park at WAITING_APPROVAL, you approve in bulk, sends fire via Instantly.

Conceptual overview

For each competitor backlink, the agent reasons:

  • Is this site a content site (where they linked to a resource) or a transactional site? (We pitch content sites.)
  • Does our content match the angle they're already endorsing? (Higher hit rate.)
  • Has anyone in our CRM already pitched this site? (Skip if recent.)
  • Is the site's DR high enough to be worth our time?

The drafted email cites the existing competitor link explicitly: "You mentioned [competitor]'s capacity tracking — we just published a different take that ...".

Endpoints

MethodPathPurpose
POST/v1/link-building/competitor-outreachStart a competitor outreach campaign
GET/v1/link-building/competitor-outreachList campaigns
GET/v1/link-building/competitor-outreach/{id}Get one campaign
GET/v1/link-building/competitor-outreach/{id}/draftsList drafts
POST/v1/link-building/competitor-outreach/{id}/approveBulk approve
POST/v1/link-building/competitor-outreach/{id}/rejectBulk reject
PATCH/v1/link-building/competitor-outreach/{id}Adjust filters / pause
DELETE/v1/link-building/competitor-outreach/{id}Cancel

POST /v1/link-building/competitor-outreach

{
  "competitorId": "cmp_monday",
  "ourContentUrl": "https://acme.com/blog/engineering-team-capacity-tracking",
  "filters": {
    "minDomainRating": 40,
    "maxDomainRating": 85,
    "linkType": "dofollow",
    "minRelevanceScore": 0.7,
    "minAchievabilityScore": 0.5,
    "excludeAlreadyContactedWithinDays": 180,
    "limit": 25
  },
  "outreach": {
    "targetingAngle": "parallel_resource",
    "emailTemplate": "tpl_competitor-replacement",
    "personalize": true,
    "approval": { "required": true }
  },
  "tags": ["q2-2026"]
}
FieldTypeRequiredDefaultNotes
competitorIdstringyesA tracked competitor (see Research · competitor)
competitorDomainstringone ofOr raw domain (auto-creates competitor record)
ourContentUrlstringyesThe asset you want to pitch as a parallel resource
filters.minDomainRating / maxDomainRatingnumberno40 / 85
filters.linkTypeenumnodofollowdofollow, nofollow, all
filters.minRelevanceScorenumberno0.7Topical relevance of the linking page to your content
filters.minAchievabilityScorenumberno0.5Heuristic for how likely you could earn the link too
filters.excludeAlreadyContactedWithinDaysnumberno180
filters.limitnumberno25Cap on accounts to pitch
outreach.targetingAngleenumnolink_insertionlink_insertion, parallel_resource, replacement, update_outdated_link
outreach.emailTemplatestringnoworkspace default
outreach.approval.requiredbooleannoworkspace policy

Response

{
  "campaignId": "ccmp_***",
  "invocationId": "inv_***",
  "agentId": "agt_***",
  "skill": "link_building.competitor_outreach",
  "status": "RUNNING",
  "estimatedCost": { "credits": 32, "durationSeconds": 360 }
}

Final summary

{
  "campaignId": "ccmp_***",
  "invocationId": "inv_***",
  "agentId": "agt_***",
  "skill": "link_building.competitor_outreach",
  "status": "AWAITING_APPROVAL",
  "creditsUsed": 30,
  "summary": {
    "competitorBacklinks": 4108,
    "afterLinkTypeFilter": 2841,
    "afterDomainRatingFilter": 1217,
    "afterRelevanceFilter": 412,
    "afterAchievabilityFilter": 178,
    "afterAlreadyContactedFilter": 91,
    "afterContactDiscovery": 27,
    "finalDrafts": 25
  },
  "topDomains": [
    {
      "domain": "engineering-blog.com",
      "drafted": true,
      "domainRating": 62,
      "relevanceScore": 0.84,
      "achievabilityScore": 0.71
    }
  ],
  "raw": "Pulled 4,108 backlinks for monday.com. Filtered to 25 high-relevance, high-achievability content sites that don't currently link to us ...",
  "files": [
    "agent-workspace/backlinks-raw.json",
    "agent-workspace/filter-decisions.csv",
    "agent-output/drafts.md"
  ]
}

Same shape as SERP outreach drafts — each draft has relationshipId, accountId, contact, subject, body, status, approvalUrl.


POST /v1/link-building/competitor-outreach/{id}/approve

Same shape as SERP outreach approve.

curl -X POST .../v1/link-building/competitor-outreach/ccmp_***/approve -d '{
  "draftIds": "all",
  "scheduleAt": "2026-05-25T09:00:00-04:00"
}'

MCP

> Pull monday.com's backlinks and pitch our capacity-tracking article to the best 25 sources.

Claude calls link_building.competitor_outreach.create.

> Show the drafts; let me approve them.

Claude calls link_building.competitor_outreach.drafts + approval loop.


Errors

StatusCodeCause
404competitor_not_found
422no_backlinks_foundCompetitor has no usable backlinks (try refreshing)
422no_drafts_producedAll backlinks filtered out — loosen filters
503ahrefs_unavailable
503apollo_unavailable

Cost

ActionCredits
Per campaign (per 25-draft cap)~30
+ per-domain contact discovery (Apollo)+0.4 each
+ per-draft LLM personalization+0.5 each
+ per email sent on approval+2 each

Use cases (string things together)

A. Steal-from-competitor weekly

for CMP in cmp_monday cmp_asana cmp_clickup; do
  curl -X POST .../v1/link-building/competitor-outreach -d "{
    \"competitorId\":  \"$CMP\",
    \"ourContentUrl\": \"https://acme.com/blog/engineering-team-capacity-tracking\"
  }"
done
curl -X POST .../v1/link-building/competitor-outreach -d '{
  "competitorId":     "cmp_monday",
  "ourContentUrl":    "https://acme.com/blog/our-replacement-article",
  "outreach":         { "targetingAngle": "replacement" }
}'

The drafted email surfaces the specific broken link as the hook.

curl -X POST .../v1/agent/invoke -d '{
  "skill": "link_hunter",
  "input": {
    "competitorIds":  ["cmp_monday"],
    "ourContentUrls": ["https://acme.com/blog/engineering-team-capacity-tracking"],
    "cadence":        "weekly"
  }
}'

On this page