# get_guide_readiness

Publish checklist: blocking gates, warnings, review link.

`GET /v1/guides/{productId}/readiness` · MCP tool `get_guide_readiness` · scope `read` · stable · since 2026-09-17

Run this before handing the draft back. blocking is the publish gates themselves (agreement, at least one live spot, a pin and a photo on every live spot, a price), the same check publishing enforces. warnings flag coordinate outliers, spots without text, missing credits, an incomplete sales page, facts past their review-by or valid-until dates, dead, parked, spam or redirected links, photos taken far from the pin or before a change at the spot, places far from their spots or in another time zone, stated distances shorter than the straight line, text search map links, dates in the text that have passed, best months missing from a month property, directions that disagree with the pins, best light outside the opening hours and extra pins far from their spot; checks holds the rows behind each warning and every reviewNotes entry. handoff lists the clicks only the creator can make (Publish guide, Publish sales page) with their studio links: plan the hand-off from the start. Send the creator the reviewUrl. For a live guide, see get_publish_status and publish_changes.

## Path parameters

- `productId` (string, required): Id of the guide (a product of type map). From list_guides or create_guide.

## Returns

200: Readiness.

- `productId` (string, required): The guide's id.
- `name` (string, required): The guide's title.
- `status` (string, required): draft, published or archived. One of `draft`, `published`, `archived`.
- `canPublish` (boolean, required): true when no publish gate is open.
- `blocking` (array of PublishGate, required): The publish gates that are open: the same check publishing enforces.
  Fields of PublishGate: https://developers.sceniq.earth/fields/publish-gate.md
- `warnings` (array of objects, required): Checks that do not block a publish but deserve a look.
  - `code` (string, required): A stable code for the warning (see the readiness guide for the list).
  - `message` (string, required): What it means, in plain words.
- `checks` (object, required): The rows behind each warning and gate.
  - `staleFacts` (array of StaleFact, required): Dated facts past their dates.
    Fields of StaleFact: https://developers.sceniq.earth/fields/stale-fact.md
  - `reviewNotes` (array of objects, required): Every reviewNotes entry in the guide.
    - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `photo`.
    - `id` (string, required): The row's id.
    - `name` (string, required): The row's name.
    - `note` (string, required): The review note.
  - `spotsWithoutSources` (number, required): Live spots without any source.
  - `links` (object, required): Link health (get_link_report has every link).
    - `total` (number, required): Links buyers can open.
    - `flagged` (array of objects, required): Links that look dead, parked or redirected.
      - `url` (string, required): The link.
      - `state` (string, required): Its state (broken, suspicious, tls, redirected).
      - `reason` (string or null, required): Why, in words.
      - `finalUrl` (string or null, required): Where a redirect ends.
      - `usedBy` (array of objects, required): Where the link is used.
        - `kind` (string, required): The kind of row.
        - `name` (string, required): The row's name.
        - `field` (string, required): The field that holds the link.
    - `unverifiable` (number, required): Links on sites that turn scripts away.
    - `unchecked` (number, required): Links not checked yet.
  - `photos` (object, required): Photo checks.
    - `farFromPin` (array of objects, required): Photos with a precise location more than 2 km from the pin.
      - `kind` (string, required): Always photo. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The photo's id.
      - `name` (string, required): The photo's caption or file.
      - `spotId` (string, required): The spot the photo belongs to.
      - `spotTitle` (string, required): The spot's title.
      - `detail` (string, required): What looks wrong.
    - `judgement` (array of objects, required): Photos whose location needs the creator's judgement.
      - `kind` (string, required): Always photo. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The photo's id.
      - `name` (string, required): The photo's caption or file.
      - `spotId` (string, required): The spot the photo belongs to.
      - `spotTitle` (string, required): The spot's title.
      - `detail` (string, required): What looks wrong.
    - `beforeChange` (array of objects, required): Photos captured before the spot's siteChange.
      - `kind` (string, required): Always photo. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The photo's id.
      - `name` (string, required): The photo's caption or file.
      - `spotId` (string, required): The spot the photo belongs to.
      - `spotTitle` (string, required): The spot's title.
      - `detail` (string, required): What looks wrong.
    - `nearDuplicates` (array of objects, required): Photos that look like another photo of the guide.
      - `kind` (string, required): Always photo. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The photo's id.
      - `name` (string, required): The photo's caption or file.
      - `spotId` (string, required): The spot the photo belongs to.
      - `spotTitle` (string, required): The spot's title.
      - `detail` (string, required): What looks wrong.
  - `places` (object, required): Place checks.
    - `farFromSpots` (array of objects, required): Places far from the spots they serve.
      - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The row's id.
      - `name` (string, required): The row's name.
      - `detail` (string, required): What looks wrong.
    - `zoneDiffers` (array of objects, required): Places in another time zone than their spot.
      - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The row's id.
      - `name` (string, required): The row's name.
      - `detail` (string, required): What looks wrong.
    - `distanceTooShort` (array of objects, required): Stated distances shorter than the straight line.
      - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The row's id.
      - `name` (string, required): The row's name.
      - `detail` (string, required): What looks wrong.
    - `searchLinks` (array of objects, required): Map links that are a text search (they can open a namesake).
      - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The row's id.
      - `name` (string, required): The row's name.
      - `detail` (string, required): What looks wrong.
  - `text` (object, required): Text checks.
    - `pastDates` (array of objects, required): Dates in the text that have passed.
      - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The row's id.
      - `name` (string, required): The row's name.
      - `field` (string, required): The field the text is in.
      - `detail` (string, required): What looks wrong.
    - `monthMismatch` (array of objects, required): Best months in the text missing from a month property.
      - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The row's id.
      - `name` (string, required): The row's name.
      - `field` (string, required): The field the text is in.
      - `detail` (string, required): What looks wrong.
    - `directions` (array of objects, required): Directions that disagree with the pins.
      - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `area`, `photo`.
      - `id` (string, required): The row's id.
      - `name` (string, required): The row's name.
      - `field` (string, required): The field the text is in.
      - `detail` (string, required): What looks wrong.
  - `light` (array of objects, required): Best light outside the opening hours.
    - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `area`, `photo`.
    - `id` (string, required): The row's id.
    - `name` (string, required): The row's name.
    - `field` (string, required): The field the text is in.
    - `detail` (string, required): What looks wrong.
  - `pins` (array of objects, required): Extra pins far from their spot.
    - `kind` (string, required): The kind of row. One of `spot`, `place`, `route`, `area`, `photo`.
    - `id` (string, required): The row's id.
    - `name` (string, required): The row's name.
    - `field` (string, required): The field the text is in.
    - `detail` (string, required): What looks wrong.
  - `agreementCurrent` (boolean, required): Whether the creator accepted the current agreement.
  - `spotCount` (number, required): Live spots.
  - `archivedSpotCount` (number, required): Archived spots.
  - `missingCoordinates` (array of objects, required): Live spots without a pin.
    - `spotId` (string, required): The spot's id.
    - `title` (string, required): The spot's title.
  - `coordinateOutliers` (array of objects, required): Spots unusually far from the others.
    - `spotId` (string, required): The spot's id.
    - `title` (string, required): The spot's title.
    - `distanceKm` (number, required): Distance from the guide's center in kilometers.
  - `outlierThresholdKm` (number, required): The distance above which a spot counts as an outlier.
  - `outsideRegion` (array of objects, required): Spots outside the region's bbox.
    - `spotId` (string, required): The spot's id.
    - `title` (string, required): The spot's title.
  - `spotsWithoutPhotos` (array of objects, required): Live spots with photos on but none uploaded.
    - `spotId` (string, required): The spot's id.
    - `title` (string, required): The spot's title.
  - `spotsWithoutText` (array of objects, required): Spots without a short or a long description.
    - `spotId` (string, required): The spot's id.
    - `title` (string, required): The spot's title.
  - `photoCount` (number, required): Photos in the guide.
  - `photosWithoutCredit` (number, required): Photos without a credit.
  - `price` (object or null, required): The active price.
    - `amountMinor` (number, required): The price in minor units (2900 is 29.00).
    - `currency` (string, required): ISO 4217 code in lower case (usd, eur, chf).
  - `chapterCount` (number, required): Chapters and collections.
  - `routeCount` (number, required): Routes.
  - `region` (MapRegion or null, required): The map region.
    Fields of MapRegion: https://developers.sceniq.earth/fields/map-region.md
  - `storeTags` (array of strings, required): Store tags.
  - `country` (string or null, required): Country code, or null for worldwide.
  - `hasThumbnail` (boolean, required): Whether a store thumbnail is set.
  - `salesPage` (object, required): The sales page.
    - `draftProblems` (array of strings, required): What the sales page draft still lacks.
    - `exists` (boolean, required): Whether a sales page draft exists.
    - `published` (boolean, required): Whether the sales page is published.
  - `lastApiWriteAt` (number or null, required): When a key last changed the guide.
- `handoff` (object, required): What the creator does in the studio.
  - `remaining` (array of strings, required): The clicks only the creator can make, still open.
  - `studioUrl` (string, required): Where the creator publishes the guide.
  - `salesPageUrl` (string, required): Where the creator publishes the sales page.
- `reviewUrl` (string, required): The guide in the studio, for the creator's review.
- `nextStep` (string, required): One sentence on what to do next.

## Examples

### A draft with open publish gates and a few warnings

```bash
curl "https://sceniq.earth/api/v1/guides/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2/readiness" \
  -H "Authorization: Bearer $SCENIQ_API_KEY"
```

MCP `tools/call`:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_guide_readiness",
    "arguments": {
      "productId": "j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2"
    }
  }
}
```

Response 200:

```json
{
  "productId": "j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2",
  "name": "American West: Parks at First Light",
  "status": "draft",
  "canPublish": false,
  "blocking": [
    {
      "code": "missing_coordinates",
      "message": "1 spot has no coordinates (Lamar Valley)"
    },
    {
      "code": "missing_photos",
      "message": "2 spots have no photo (Lamar Valley, Taft Point)"
    }
  ],
  "warnings": [
    {
      "code": "spots_without_text",
      "message": "1 spot(s) have neither a short nor a long description"
    },
    {
      "code": "sales_page_incomplete",
      "message": "Sales page draft: the hero needs between 2 and 6 bullets"
    },
    {
      "code": "no_thumbnail",
      "message": "No store thumbnail set (the creator picks it in the dashboard)"
    },
    {
      "code": "review_due",
      "message": "1 row is past its review-by date; re-check the facts and set a new reviewBy"
    },
    {
      "code": "stale_facts",
      "message": "2 dated facts have run out or not been checked recently (notices, fees, hours, timetables); see checks.staleFacts or list_stale_notices"
    },
    {
      "code": "link_problems",
      "message": "1 link is dead, parked, spam, redirected elsewhere or failing TLS; see checks.links (confirm a false alarm with set_link_verified)"
    }
  ],
  "checks": {
    "staleFacts": [
      {
        "kind": "spot",
        "id": "k1736b344br1c7m8qk8ks4sfndxyyftj",
        "name": "Glacier Point",
        "field": "reviewBy",
        "reason": "review_due",
        "date": "2026-09-15",
        "detail": "facts were due for a new check on 2026-09-15"
      },
      {
        "kind": "place",
        "id": "km73j9h5g1f7d3s9a5p1p7j3v9y5t1r7",
        "name": "Old Faithful Inn",
        "field": "schedule",
        "reason": "ended",
        "date": "2026-09-27",
        "detail": "hours valid until 2026-09-27"
      },
      {
        "kind": "route",
        "id": "kx7f2h8j4k0k6z2x8c4v0b6n2m8q4w0e",
        "name": "Fairy Falls trail",
        "field": "status",
        "reason": "ended",
        "date": "2026-09-25",
        "detail": "the closed notice ran until 2026-09-25; update or clear it"
      }
    ],
    "reviewNotes": [
      {
        "kind": "spot",
        "id": "k1709e2vj4sk8q6x0d3m5r7t9w1y3b5c",
        "name": "Grand Prismatic Spring",
        "note": "The overlook pin comes from your GPX of 18 September; please confirm it. The trail distance is from the NPS page (0.6 mi each way)."
      },
      {
        "kind": "spot",
        "id": "k17rwzt006kbqwjbs5jrqk4jjf5srec9",
        "name": "Lamar Valley",
        "note": "No pin yet: the creator is sending the pullout they use for the bison herds."
      }
    ],
    "spotsWithoutSources": 7,
    "links": {
      "total": 26,
      "flagged": [
        {
          "url": "https://www.nps.gov/yose/planyourvisit/glacierpoint.htm",
          "state": "broken",
          "reason": "http_404",
          "finalUrl": null,
          "usedBy": [
            {
              "kind": "spot",
              "name": "Glacier Point",
              "field": "links"
            }
          ]
        }
      ],
      "unverifiable": 1,
      "unchecked": 2
    },
    "photos": {
      "farFromPin": [],
      "judgement": [
        {
          "kind": "photo",
          "id": "kg7m9n1b3v5c7x9z1k3k5j7h9g1f3d5s",
          "name": "Tunnel View as a December storm clears",
          "spotId": "k17bc3xz8h6f4d2s0q9w7e5r3t1y2v4j",
          "spotTitle": "Tunnel View",
          "detail": "location rests on judgement, not a geotag or a landmark"
        }
      ],
      "beforeChange": [],
      "nearDuplicates": []
    },
    "places": {
      "farFromSpots": [],
      "zoneDiffers": [],
      "distanceTooShort": [],
      "searchLinks": []
    },
    "text": {
      "pastDates": [],
      "monthMismatch": [],
      "directions": []
    },
    "light": [],
    "pins": [],
    "agreementCurrent": true,
    "spotCount": 12,
    "archivedSpotCount": 1,
    "missingCoordinates": [
      {
        "spotId": "k17rwzt006kbqwjbs5jrqk4jjf5srec9",
        "title": "Lamar Valley"
      }
    ],
    "coordinateOutliers": [],
    "outlierThresholdKm": 1590,
    "outsideRegion": [],
    "spotsWithoutPhotos": [
      {
        "spotId": "k17rwzt006kbqwjbs5jrqk4jjf5srec9",
        "title": "Lamar Valley"
      },
      {
        "spotId": "k17hdgc1c8j423kgq30t9x5hyv1tv8yb",
        "title": "Taft Point"
      }
    ],
    "spotsWithoutText": [
      {
        "spotId": "k17rwzt006kbqwjbs5jrqk4jjf5srec9",
        "title": "Lamar Valley"
      }
    ],
    "photoCount": 31,
    "photosWithoutCredit": 0,
    "price": {
      "amountMinor": 2900,
      "currency": "usd"
    },
    "chapterCount": 5,
    "routeCount": 2,
    "region": {
      "label": "Yellowstone and Yosemite",
      "centerLat": 41.2,
      "centerLon": -115,
      "defaultZoom": 5,
      "bbox": [
        -120,
        37.4,
        -109.8,
        45.2
      ]
    },
    "storeTags": [
      "photography",
      "hiking",
      "road-trips"
    ],
    "country": "US",
    "hasThumbnail": false,
    "salesPage": {
      "draftProblems": [
        "the hero needs between 2 and 6 bullets"
      ],
      "exists": true,
      "published": false
    },
    "lastApiWriteAt": 1790586840000
  },
  "handoff": {
    "remaining": [
      "Publish guide: the creator puts the draft on sale in the studio (Publish)",
      "Publish sales page: the creator publishes the sales page draft in the studio"
    ],
    "studioUrl": "https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2",
    "salesPageUrl": "https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2/listing"
  },
  "reviewUrl": "https://creators.sceniq.earth/products/j5738kd1q9x2m7v4c6b8n0p3r5t1w9y2",
  "nextStep": "Resolve the blocking items, then ask the creator to review the draft in the dashboard"
}
```

## Errors

- `invalid_argument` (400): A required field is missing, a field is unknown, or a value does not match its type (the Convex validator's path and value are in the message).
- `unauthenticated` (401): The request carries no key. Send it as Authorization: Bearer sk_sceniq_... (or X-Api-Key).
- `invalid_api_key` (401): The key is unknown, revoked or expired.
- `forbidden` (403): The key belongs to a creator account that is no longer active.
- `not_found` (404): The id does not exist or belongs to another creator. The two answers are identical on purpose, so ids never reveal what exists.
- `rate_limited` (429): Over a limit: requests per key per minute, per creator per hour, uploads per key per minute, or check_links per guide per hour.
- `internal_error` (500): An unexpected failure. The message is hidden on purpose.

Reference: https://developers.sceniq.earth/reference/get_guide_readiness
