---
title: "Competitors' referring domains the target lacks, priced and held"
method: POST
path: "/v1/targets/gap"
tags: ["Research"]
---

# Competitors' referring domains the target lacks, priced and held

`POST /v1/targets/gap`

## Request

- Base URL: `https://api.placementapi.com`
- URL: `https://api.placementapi.com/v1/targets/gap`
- Auth: HTTP bearer

Domains linking to the competitors and not to the target, joined to the catalogue: rows we can sell come back as quote lines (held for 4 hours, orderable with quote_id exactly like /v1/quote lines) plus competitors_linking and linking_competitors; what we cannot sell is a count and a sample. Suspect domains are excluded. Without competitors, DataForSEO's backlink competitors are used and competitors_source says so. Cached 24h per target and competitor set; 20 fresh fetches per customer per day.

## Request body

- object
  - `target_url` string, required
  - `competitors` string[]
  - `topic` string
  - `placement_type` string
  - `limit` integer

## Response `201`

OK

- object
  - `target_domain` string
  - `competitors` string[]
  - `competitors_source` string
  - `cached` boolean
  - `fetched_at` string
  - `gap_total` integer
  - `gap_fetched` integer
  - `carried` integer
  - `carried_share` number
  - `quote_id` string, nullable
  - `expires_at` string, nullable
  - `ttl_seconds` integer
  - `binding` boolean
  - `total_credits` integer
  - `excluded` object
  - `rows` object[]
    - `offer_id` string
    - `site_id` string, nullable: Null on blind inventory.
    - `inventory_mode` 'named' | 'pre_approval' | 'blind': The most important field. 'named' = a specific, identified domain you can inspect before ordering. 'pre_approval' = the vendor proposes candidate domains and the buyer approves them BEFORE placement. 'blind' = a promise (e.g. DR50+, finance) where the domain is assigned at fulfilment with no veto. Only 'named' carries a site_id. Never present a pre_approval or blind offer as though a specific site were secured, and never price-compare a specification against a named domain as the same product.
    - `placement_type` 'guest_post' | 'niche_edit' | 'link_insert' | 'homepage_link' | 'media_placement'
    - `price_credits` integer: Held price. Credits. 1 credit = 1 US cent.
    - `dr` number, nullable: The vendor's claim. On a subdomain, the parent's number.
    - `traffic` number, nullable
    - `verification` 'ok' | 'suspect' | 'unverified' | 'null', nullable: Our independent verdict on the claimed authority; no supplier publishes it. 'suspect' = high link authority with little or no organic search presence, which is what a link farm looks like — do not plan around suspect domains. 'ok' = measured, and search presence matches the rating. 'unverified' = not measured yet, which is not a pass.
    - `verified_dr` number, nullable: DataForSEO backlinks rank, 0-1000; corroborates, does not replace dr.
    - `verified_traffic` number, nullable
    - `organic_keywords` integer, nullable
    - `referring_domains` integer, nullable
    - `spam_score` number, nullable
    - `subdomain_of` string, nullable
    - `quality_reasons` string[]: Which rules made verification read suspect: high_authority_no_traffic, high_authority_no_keywords, spam_score, subdomain_without_own_footprint, saturated_outbound. Empty when not suspect.
    - `restricted` string[]: gambling / adult / piracy when the site is one, from the domain name and a short topic list. Such rows appear only when asked for (include_restricted, or a topic/accepts naming the vertical).
    - `outbound_external` integer, nullable
    - `inbound_domains` integer, nullable
    - `cc_pagerank` number, nullable
    - `leader_links` LeaderLinks, nullable: Common Crawl web graph, root sites only (null on subdomains): how many of a topic's top-ranking sites the domain links to, keyed by topic.
    - `survival` Survival, nullable: What happened to the placements WE bought on this publisher. Our crawler re-checks every delivered link at 0/7/30/60/90/180/365 days. Null under three orders.
      - `orders` integer
      - `checks` integer
      - `live_share` number
      - `live_90d_share` number, nullable
      - `median_days_to_missing` number, nullable
      - `dofollow_share` number, nullable
      - `noindex_share` number, nullable
      - `updated_at` string, date-time
    - `supplier_reliability` SupplierReliability: How the seller behind the line has performed for us (fulfilment, on-time delivery, link survival, failures, refunds) over n submitted orders. Never a name. Within 5% of price the basket prefers the better band; 'unknown' (under five orders) is judged on price alone.
      - `band` 'high' | 'medium' | 'low' | 'unknown'
      - `n` integer
    - `placement_score` PlacementScore, nullable: Placement Score v1: { score 0-100, version, confidence high|medium|low, components each 0-100 or null, capped }. Weights (authority 25 / visibility 25 / quality 30 / graph 10 / survival 10) are stated, not fitted; unmeasured components drop out and the rest re-weight; a suspect publisher never scores above 40. Derived from the fields beside it, so it can be checked. Does NOT include observed effectiveness, relevance to your brief, or supplier reliability. Quote the components, not just the number.
      - `score` integer
      - `version` string
      - `confidence` 'high' | 'medium' | 'low': Share of the weight that had a measurement behind it.
      - `components` object
        - `authority` number, nullable
        - `visibility` number, nullable
        - `quality` number, nullable
        - `graph` number, nullable
        - `survival` number, nullable
      - `capped` 'suspect' | 'null', nullable
    - `market_reference` MarketReference, nullable: The median ASK of comparable placements (same type, inventory mode and claimed-DR decade), not a clearing price — say 'market reference', never 'fair value'. own_asks is the spread of asks across suppliers for this exact domain and type, as counts and credits only. ask_history is null under 14 days of observations. Null on a thin band.
      - `reference_credits` integer
      - `method` 'band_median_v1'
      - `comparables_n` integer
      - `vs_reference_pct` number: This price against the reference, in percent; negative is cheaper.
      - `assessment` 'under' | 'at' | 'over': ±15% band around the reference.
      - `own_asks` object
        - `listings` integer
        - `suppliers` integer
        - `lowest` integer
        - `median` integer
        - `highest` integer
      - `ask_history` object, nullable
        - `first_seen_at` string, date-time
        - `days_observed` integer
        - `first_credits` integer
        - `change_pct` number
    - `plausibility` Plausibility, nullable: Where this price sits among comparable domains (same placement type, inventory mode and claimed-DR decade). flag 'low' = under the 10th percentile, which is bought authority more often than it is a bargain; 'high' = above the 90th. Null when the band had too few domains to describe.
      - `pct` number
      - `band` string
      - `flag` 'low' | 'ok' | 'high'
      - `n` integer: Domains behind the distribution.
    - `demand` Demand, nullable: Observed demand: distinct buyers who bought the domain in twelve months and the niches they bought for. Null under the three-buyer floor. Nothing about any one buyer is ever here.
      - `buyers_12m` integer
      - `purchases_12m` integer
      - `niches` object[]
        - `topic` string
        - `buyers` integer
    - `why` string[]: Factual sentences behind the pick, derived from the fields on this line and the brief — cite them. Prose; do not parse it.
    - `intelligence` object: Present only when the deployment has placement intelligence configured and this placement was actually judged; absent means not judged, which is not the same as judged and rejected. An advisory semantic judgment. In a `recommended` basket running in configured `rank` mode a rank-usable judgment can reorder a line within the explicit demand/leader priorities; it can never exclude a placement, an alternative or a publisher, and missing, invalid, failed or below-threshold evidence leaves the deterministic result — and every price — unchanged. The service judges a sampled publisher page resolved by site id, not the offered placement itself, so a below-threshold reading is not evidence against buying this slot. `topical_fit` and `confidence` are on the service's own scale — not a probability of SEO impact. No provider payload, evidence text or customer id is ever included.
      - `status` string: computed | cached when a judgment exists; disabled | insufficient_evidence | no_evidence | invalid_evidence | unavailable | budget_exhausted | busy | invalid_response | timeout otherwise.
      - `rank_usable` boolean: True only in rank mode when the service's own policy called the judgment usable. In a `recommended` basket a rank-usable judgment is what can reorder the placement; no judgment, usable or not, removes one.
      - `topical_fit` number, nullable: The judged fit to the brief's recognized topics, on the service's own scale; null when nothing usable was produced.
      - `confidence` number, nullable
      - `editorial_format` string, nullable
      - `policy_version` string, nullable
    - `relevance` unknown
    - `alternatives` QuoteAlternative[]
      - `offer_id` string
      - `site_id` string, nullable
      - `placement_type` 'guest_post' | 'niche_edit' | 'link_insert' | 'homepage_link' | 'media_placement'
      - `price_credits` integer
      - `dr` number, nullable
      - `verification` 'ok' | 'suspect' | 'unverified' | 'null', nullable: Our independent verdict on the claimed authority; no supplier publishes it. 'suspect' = high link authority with little or no organic search presence, which is what a link farm looks like — do not plan around suspect domains. 'ok' = measured, and search presence matches the rating. 'unverified' = not measured yet, which is not a pass.
      - `plausibility_pct` number, nullable
    - `turnaround_days` integer, nullable
    - `topics` string[]
    - `guarantees` unknown
    - `order_requirements` OrderRequirements, nullable: What you MUST send, what you MAY send, and what you can buy, normalised across suppliers. `required` lists the fields to include in POST /v1/orders. Read `confidence`: 'observed' and 'documented' are reliable; 'assumed' means the confirmation step may ask for something not listed.
      - `required` string[]: Always includes target_url; anchor_text is absent only where the publisher writes the anchor.
      - `optional` string[]
      - `content` object
        - `supplied_allowed` boolean: Whether you may write the article yourself.
        - `spec` ContentSpec, nullable: The brief to write against when the buyer supplies copy. Null when copy cannot be supplied.
          - `word_count_min` integer, nullable
          - `word_count_max` integer, nullable
          - `links_allowed` integer
          - `anchor_types_forbidden` string[]
          - `rules` string[]: Editorial rules in the publisher's own words.
        - `options` ContentOption[]
          - `tier` 'supplied' | 'included' | 'standard' | 'native' | 'papi_written'
          - `vendor_label` string, nullable: Pass as content_tier for content_mode 'service'.
          - `price_credits` integer: Add-on cost. Credits. 1 credit = 1 US cent.
          - `word_count` integer, nullable
          - `note` string, nullable
        - `due_days` integer, nullable: Days a supplied article may take to arrive after ordering (14); null where the publisher writes.
      - `speed` object
        - `standard_days` integer, nullable
        - `expedited_days` integer, nullable
        - `expedited_surcharge_bps` integer, nullable
      - `confirmation_required` boolean: True when a human at the supplier confirms the line before it is placed; treat the order as pending rather than done.
      - `rules` string[]: Placement rules the buyer must respect regardless of who writes the copy.
      - `confidence` 'observed' | 'documented' | 'assumed'
    - `competitors_linking` integer
    - `linking_competitors` string[]
  - `not_carried` integer
  - `not_carried_sample` object[]
    - `domain` string
    - `competitors_linking` integer
    - `link_rank` integer, nullable
  - `cache` object
  - `next` object

## Other responses

- `400`: Malformed request. `error` is `bad_request` (with a zod `detail`), `invalid_json`, or `unknown_parameter` / `unknown_field` (with `unknown[]` and `accepted[]`).
- `401`: Missing, malformed or revoked Bearer credential: `{ error: "unauthorized" }`.
- `403`: `insufficient_scope` when the key lacks the `order` scope; `customer_key_required` when the operator token is used where a customer must be attributable.
- `409`: `no_competitors`: none found sharing referring domains; name some.
- `429`: `gap_budget_exhausted`: 20 new gap fetches per day.
- `503`: `server_misconfigured` when the store is not configured; `upstream_unfunded` when the measurement provider's prepaid balance is exhausted (fresh profiles, gap maps and SERPs pause; cached results and catalogue are unaffected); `upstream_unavailable` on a provider error; `payments_unavailable` when card payments are not configured.

---

[API](https://skmtc.dev/placementapi/apis/placement-api.md) · [All operations](https://skmtc.dev/placementapi/apis/placement-api/llms.txt) · [OpenAPI document](https://skmtc.dev/placementapi/apis/placement-api/revisions/fc4e7866eaf7?raw)
