public

Gather facts from this directory’s listings’ own websites

Reads each listing’s website and writes what it finds into typed attributes prefixed by source — site_title, site_description, site_og_image, site_headings, site_text_excerpt and the rest. Intended as seed material for writing your own copy, not as text to publish: it is what the business says about itself, gathered verbatim.

The full raw result is also stored as a SourceSnapshot on the listing, so a description written from it can cite the evidence it came from.

Asynchronous. The response reports what was queued, not what was gathered; poll GET .../research for coverage.

Send declareFields: true on your first call. Research only writes into fields the directory has declared a template for. Without them the sweep succeeds and writes nothing, which is the one confusing failure mode this endpoint has.

Only listings with a resolvable website are eligible — website, url, homepage or organizerWebsite in canonicalFields, with a series_of child inheriting its parent series’ site. listingsWithoutUrl is the honest gap: no number of runs will help those.

Refreshing. Listings read within staleAfterDays (default 90) are skipped, so running this on a schedule re-reads only what has aged. Fields on templates marked { derived: true } are updated in place; anything else is filled only when blank, so a description someone wrote by hand is never overwritten by a sweep.

Respects enrichmentPolicy.probe === false, which short-circuits before anything is queued.

post/public/v1/directories/{directory}/research

Request

  • Base URL: https://api.epicdirectories.com
  • URL: https://api.epicdirectories.com/public/v1/directories/{directory}/research
  • Auth: API key in header x-api-key

Path parameters

directorystring required

Headers

Idempotency-Keystring

Optional. Send a unique key per logical operation to make retries safe. 1-256 characters, and only letters, digits, - and _ — colons and other separators are rejected with 400. A retry with the same key replays the original response (status + body) instead of re-executing. Cached for 24h. Reusing a key with a different request body returns 409 — note that a timestamp in the body (e.g. fetchedAt) turns an otherwise-stable key into a permanent 409, so either omit it (snapshots default it server-side) or fold a payload digest into the key. Skipped on 5xx responses (transient errors should be retried fresh).

x-api-keystring required

API Key for authentication

Request body

limitnumber

How many listings to queue this run. Capped at 100 regardless of what you send: each job is a request to somebody else's server, and a directory with ten thousand listings must not be able to point a burst that size at one host. The response reports deferred when the cap bit, and the next run picks up where this one stopped.

forceboolean

Re-read every listing regardless of how recently it was last read. Off by default, so a repeated sweep costs only the listings that have gone stale rather than re-fetching the whole directory.

staleAfterDaysnumber

Treat data older than this many days as stale and re-read it. This is the knob for periodic refresh — run the same sweep on a schedule and it re-reads only what has aged past the window. 0 means "everything is stale", which is force by another name.

sourcesstring[]

Which sources to gather from. Defaults to site alone.

Each writes into fields prefixed with its own name — site_title, google_rating — so two sources describing the same thing can never overwrite each other. That convention exists because the unprefixed form already went wrong: a bare rating held 2,418 values from a partner import and one from Google, with nothing recording which was which.

google_places is billable. Google charges per request, where site costs only a fetch, so it is never included by default — a sweep over thousands of listings has to ask for it. Matches are confidence-gated: Places returns its best guess with no score, and a listing whose title is not really a place would otherwise be attached to an unrelated nearby business.

declareFieldsboolean

Create the attribute templates these sources write into, if the directory has not declared them already.

Send this once, on your first call. Research only writes into fields the directory has declared — without a template for site_title there is nowhere for the title to go, and the sweep succeeds while writing nothing. This declares all of them in one step instead of eleven separate calls.

Templates it creates are marked { derived: true, source }, which is what allows later sweeps to refresh them. Templates that already exist are left exactly as they are — if you declared site_title yourself and filled it in by hand, this will not quietly convert it into a field a sweep may overwrite.

ingestOgboolean

Fetch each page's og:image and store it as a site_og media asset, rather than keeping only the URL. On by default.

The URL alone means every image you render is a hotlink to someone else's CDN. These are marketing sites — they redesign, change host, and rotate cache-busting paths, and when they do your listing shows a broken image with nothing to say it happened. Importing once makes the bytes yours.

Costs one fetch and one stored image per listing, so set false if you only want the text fields. A listing that already has a site_og is left alone — re-running updates the site_og_image field but never replaces the stored asset.

listingSlugsstring[]

Research these listings specifically, by slug, instead of letting the sweep choose.

A named set is an instruction, so the staleness window is bypassed — asking for a listing by name gets it re-read. Unlike a screenshot this destroys nothing: each read is stored as its own snapshot, so the previous evidence survives.

Slugs that match nothing come back as unmatchedSlugs rather than being silently dropped. Still subject to the per-run cap.

Example request

{
  "listingSlugs": [
    "acme-digital",
    "bizapedia"
  ]
}

Response

Research queued; body reports the counts per source

Changes

No recorded changes to this operation across all 1 revision of this API.