Keystone Developers
Open Keystone
API reference

Internal API

Onboarding

21 endpoints.

POST/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/assets

Ingest Assets

Checkpointed batch of downloaded+stored assets (metadata + GCS blob name + DOM signals). Idempotent by (crawl_attempt_id, asset_url).

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonIngestAssetsBody
FieldTypeDescription
assetsIngestAssetItem[]
IngestAssetItem[] fields
FieldTypeDescription
asset_urlrequiredstring
asset_typerequiredstring
page_idstring | null
asset_hoststring | null
mime_typestring | null
alt_textstring | null
source_page_urlstring | null
widthinteger | null
heightinteger | null
byte_sizeinteger | null
checksum_sha256string | null
download_statusstring | null
download_errorstring | null
storage_statusstring | null
storage_errorstring | null
storage_providerstring | null
storage_bucketstring | null
storage_blob_namestring | null
dom_signalsobject | null

Responses

200Successful Response
application/jsonSuccessResponse_IngestAssetsData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredIngestAssetsData
IngestAssetsData fields
FieldTypeDescription
createdintegerdefault 0
updatedintegerdefault 0
metadataResponseMetadata | null
ResponseMetadata fields
FieldTypeDescription
paginationPaginationMetadata | null
PaginationMetadata fields
FieldTypeDescription
limitrequiredinteger
next_cursorstring | null
prev_cursorstring | null
has_morerequiredboolean
has_prevbooleandefault false
total_countinteger | null
status_countsobject | null
object | null fields

Map of string to integer

lifecycle_countsLifecycleCounts | null
LifecycleCounts fields
FieldTypeDescription
leadintegerdefault 0
prospectintegerdefault 0
customerintegerdefault 0
former_customerintegerdefault 0
classification_countsClassificationCounts | null
ClassificationCounts fields
FieldTypeDescription
signalobject
object fields

Nested object (not expanded)

touchobject
object fields

Nested object (not expanded)

stageobject
object fields

Nested object (not expanded)

metaResponseMeta | null
ResponseMeta fields
FieldTypeDescription
totalinteger | null
total_countinteger | null
pageinteger | null
per_pageinteger | null
  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/classify

Classify Crawl Pages

Label every crawled page and return the fan-out routing table (W3).

One cheap batched LLM call over compact page descriptors. The response is the engine's whole work list: ``batches`` (one extract-domain call each), ``blog_post_page_ids`` (one extract-blog-post call each) and ``other_page_ids``. Every page appears in at least one of the three — a page the classifier missed is assigned ``other`` and reported in ``unrouted_page_ids``, never dropped.

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_ClassifyPagesData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredClassifyPagesData
ClassifyPagesData fields
FieldTypeDescription
routingobject
object fields

Map of string to string[]

Nested object (not expanded)

batchesClassifyBatchData[]
ClassifyBatchData[] fields

ClassifyBatchData (not expanded)

blog_post_page_idsstring[]
string[] fields
other_page_idsstring[]
string[] fields
unrouted_page_idsstring[]
string[] fields
page_countintegerdefault 0
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/complete

Complete Crawl

Finalize the crawl attempt. On ``completed`` runs media promotion inline (scoped to this attempt) so scraped images enter the photo library.

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonCompleteCrawlBody
FieldTypeDescription
statusrequiredstring
countersCompleteCrawlCounters | null
CompleteCrawlCounters fields
FieldTypeDescription
pages_scrapedinteger | null
pages_succeededinteger | null
pages_failedinteger | null
assets_discoveredinteger | null
summary_jsonobject | null
error_messagestring | null

Responses

200Successful Response
application/jsonSuccessResponse_CompleteCrawlData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredCompleteCrawlData
CompleteCrawlData fields
FieldTypeDescription
statusrequiredstring
promotedintegerdefault 0
media_promotedintegerdefault 0
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/extract-blog-post

Extract Blog Post Fragment

Extract one blog post from one page (W5).

The finest fan-out grain: one call per post is what restores full article bodies. The engine treats a post that exhausts its retries as best-effort — it drops the fragment and merge's CSS fallback covers the post.

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonExtractBlogPostBody
FieldTypeDescription
page_idrequiredstring

Responses

200Successful Response
application/jsonSuccessResponse_ExtractBlogPostData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredExtractBlogPostData
ExtractBlogPostData fields
FieldTypeDescription
page_idrequiredstring
fragmentobject
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/extract-domain

Extract Domain Fragment

Extract one routed batch (≤5 pages) for one data domain (W4).

The batch's full page content plus the domain's current-SOR slice go into one LLM call whose whole output budget belongs to this batch. Returns a payload-shaped fragment — off-domain collections included, because an FAQ sitting on a service page must survive a classifier mislabel.

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonExtractDomainBody
FieldTypeDescription
domainrequiredstring
page_idsstring[]
string[] fields

Responses

200Successful Response
application/jsonSuccessResponse_ExtractDomainData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredExtractDomainData
ExtractDomainData fields
FieldTypeDescription
domainrequiredstring
page_idsstring[]
string[] fields
fragmentobject
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/extract-findings

Extract Findings

Sweep every crawled page for off-schema value → typed ``extra:*`` contexts (W6).

Additive by design: an empty crawl returns an empty list rather than failing, and malformed entries are dropped instead of costing the good ones.

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonExtractFindingsBody
FieldTypeDescription
captured_domainsstring[]
string[] fields

Responses

200Successful Response
application/jsonSuccessResponse_ExtractFindingsData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredExtractFindingsData
ExtractFindingsData fields
FieldTypeDescription
contextsTypedContextData[]
TypedContextData[] fields

TypedContextData (not expanded)

pages_reviewedintegerdefault 0
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

GET/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/fetched-urls

Fetched Urls

Normalized URLs already persisted for this attempt — the scrape job seeds its visited-set from this so a retry skips completed pages.

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_FetchedUrlsData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredFetchedUrlsData
FetchedUrlsData fields
FieldTypeDescription
urlsstring[]
string[] fields
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/heartbeat

Heartbeat Crawl Attempt

Proof of life from the scrape job, independent of ingest traffic.

Pages reach sor per batch and assets only after the crawl, so a job can be busy for longer than the stale window without calling ``/pages`` or ``/assets`` — most plainly a retry that re-crawls the pages a killed execution already persisted. The job beats this on a timer for the whole crawl + asset pass. No-op (``beat=false``) once the attempt is terminal, so a superseded execution cannot keep a finished run looking alive.

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_CrawlHeartbeatData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredCrawlHeartbeatData
CrawlHeartbeatData fields
FieldTypeDescription
beatrequiredboolean
last_heartbeat_atinteger | null
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

GET/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/pages

List Pages

Pages of a crawl attempt, in one of two shapes (design §11).

``fields=descriptor`` (default): compact classifier descriptors — url, title, H1/H2 headings, first-500-char excerpt. Plain parsing, no LLM. ``fields=content``: full untruncated page text for the extractors, from the same source the legacy extraction path reads (parity contract).

NOTE: ``fields=content`` has NO consumer in the pipeline any more. It existed only to ship page text to the engine's extraction activities; those now run inside sor (``/classify``, ``/extract-domain``, …) and read the pages straight from the repository. Kept for ad-hoc inspection pending a decision on removing it.

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
fieldsquerystringdefault "descriptor"
x-internal-api-keyheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_Union_PageDescriptorsData__PageContentsData__
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredPageDescriptorsData | PageContentsData
PageDescriptorsData | PageContentsData fields
PageDescriptorsData
FieldTypeDescription
pagesPageDescriptorData[]
PageDescriptorData[] fields

Nested object (not expanded)

PageContentsData
FieldTypeDescription
pagesPageContentData[]
PageContentData[] fields

Nested object (not expanded)

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/crawl-attempts/{attempt_id}/pages

Ingest Pages

Checkpointed batch of crawled pages. Idempotent via the (crawl_attempt_id, normalized_url) unique constraint.

Parameters

NameInTypeDescription
attempt_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonIngestPagesBody
FieldTypeDescription
pagesIngestPageItem[]
IngestPageItem[] fields
FieldTypeDescription
urlrequiredstring
normalized_urlrequiredstring
titlestring | null
http_statusinteger | null
content_typestring | null
depthintegerdefault 0
markdownstring | null
cleaned_htmlstring | null
raw_textstring | null
metadata_jsonobject | null
links_jsonobject | null
images_jsonobject[] | null
object[] | null fields

Nested object (not expanded)

crawl_errorstring | null

Responses

200Successful Response
application/jsonSuccessResponse_IngestPagesData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredIngestPagesData
IngestPagesData fields
FieldTypeDescription
createdintegerdefault 0
updatedintegerdefault 0
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

PATCH/api/v1/internal/workflow-engine/onboarding/photos/tags

Update Photo Tags

Merge vision categories into ``photo_metadata.tags`` (S5 / design §13 [3]).

Set-union per photo — tags an admin or an earlier pass added are never dropped. Unknown (or deleted) photo_ids are skipped and reported rather than 404-ing the batch: the categoriser's write must land for every photo that still exists.

Parameters

NameInTypeDescription
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonPhotoTagsBody
FieldTypeDescription
updatesPhotoTagUpdateItem[]
PhotoTagUpdateItem[] fields
FieldTypeDescription
photo_idrequiredstring (uuid)
tagsstring[]
string[] fields

Nested object (not expanded)

Responses

200Successful Response
application/jsonSuccessResponse_PhotoTagsData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredPhotoTagsData
PhotoTagsData fields
FieldTypeDescription
updatedintegerdefault 0
skippedstring[]
string[] fields
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/assemble

Assemble Run Payload

Assemble every fan-out fragment into one payload and merge it (W6).

Concatenation only — dedup is merge planning's job. Routes through the same ``apply_assembled_merge`` as ``/runs/{run_id}/merge`` so the fan-out never grows a second promotion path; provenance is stamped ``website scrape fanout``. Response data is the merge counts summary.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonAssemblePayloadBody
FieldTypeDescription
fragmentsobject[]
object[] fields
contextsobject[]
object[] fields
extract_attempt_idstring (uuid) | null

Responses

200Successful Response
application/jsonSuccessResponse_dict_str__Any__
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredobject
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/categorise-images

Categorise Run Images

Categorise the run's promoted images and auto-assign the logo slots (W7).

One deterministic logo shortlist + one capped multimodal LLM call + two writes (tags merged, slots filled only-if-empty). The engine is a thin orchestrator over this call: all the vision logic and every guardrail — the shortlist-only logo pick, the >=180px favicon floor, the never-clobber slot rule — live in sor, next to the photo data they judge.

Takes no body. Same 200-with-``status`` contract as ``/stages/{stage}``: a run with no photos comes back ``skipped`` (the LLM is never called) and a domain failure comes back ``failed`` for the engine to interpret, while infra faults — and an LLM reply that should simply be re-asked — 5xx so Temporal retries them.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_CategoriseImagesData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredCategoriseImagesData
CategoriseImagesData fields
FieldTypeDescription
statusstringdefault "completed"
reasonstring | null
photosintegerdefault 0
attachedintegerdefault 0
tags_updatedintegerdefault 0
shortliststring[]
string[] fields
logostring | null
faviconstring | null
assignedobject
object fields

Map of string to string

skippedobject
object fields

Map of string to string

errorstring | null
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/crawl-attempts

Create Crawl Attempt

Open a crawl attempt for a run. Idempotent by natural key: if the run already has a *running* attempt (a retried CreateCrawlAttempt activity), it is returned instead of opening a second one. ``Idempotency-Key`` is accepted for tracing/forward-compat but the running-attempt check is the guard.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
Idempotency-Keyheaderstring | null
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonCreateCrawlAttemptBody
FieldTypeDescription
crawler_providerstringdefault "crawl4ai"

Responses

200Successful Response
application/jsonSuccessResponse_CreateCrawlAttemptData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredCreateCrawlAttemptData
CreateCrawlAttemptData fields
FieldTypeDescription
crawl_attempt_idrequiredstring
reusedbooleandefault false
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/enrich

Enrich Run

Run WS4 enrichment for one run (design §14) — the whole pass in one call.

Deterministic quality gate over the run's business → (only when it flags something) one fact-locked LLM call → partial payload through ``apply_assembled_merge`` with ``source_kind: "enrichment"``. When the gate flags nothing and the FAQ count is already sufficient the LLM is never called and the response is ``status="skipped"``.

No request body and no idempotency key: the gate re-reads current SOR state every call, so an already-enriched business is simply no longer thin and a repeat invocation short-circuits. That is what makes this endpoint safe for the console to expose as a button later — a fixed per-run key would instead swallow a deliberate second pass.

Failure split matches ``/stages/{stage}``: a stage-domain failure returns **200** with ``status="failed"`` so the engine applies its own fatality policy (enrichment is best-effort), while infra faults — and a malformed LLM reply, which is worth re-asking — 5xx so Temporal retries.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_EnrichRunData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredEnrichRunData
EnrichRunData fields
FieldTypeDescription
statusrequiredstring
flaggedintegerdefault 0
flagged_fieldsstring[]
string[] fields
reasonsobject
object fields

Map of string to integer

faq_gapintegerdefault 0
llm_calledbooleandefault false
enrichedintegerdefault 0
faqs_addedintegerdefault 0
mergeobject | null
errorstring | null
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/merge

Merge Run

Merge an engine-assembled extraction payload into the SOR (S4).

The single promotion boundary: the WS2 fan-out assembler and WS4 enrichment land through the same ``merge_payload`` the legacy chain uses. Typed ``contexts`` list entries (``extra:<kind>``) each become their own business_context_versions row. Response data is the merge counts summary.

Failures 5xx on purpose (unlike ``/stages/{stage}``): the merge activity's Temporal retry policy treats transport/5xx as retryable and 4xx as fatal, which is exactly the split a planner-LLM hiccup vs a bad payload needs.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonMergeRunBody
FieldTypeDescription
payloadrequiredobject
provenancerequiredMergeProvenance
MergeProvenance fields
FieldTypeDescription
source_kindrequiredstring
extract_attempt_idstring (uuid) | null

Responses

200Successful Response
application/jsonSuccessResponse_dict_str__Any__
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredobject
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

GET/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/photos

List Run Photos

Read-only compact list of the run's promoted photos (scrape-source, live) — the same projection the in-sor categoriser scores, exposed for inspection and for any caller that wants the raw inventory. See ``image_categorisation.run_photo_view`` for the shape.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_RunPhotosData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredRunPhotosData
RunPhotosData fields
FieldTypeDescription
photosRunPhotoData[]
RunPhotoData[] fields

RunPhotoData (not expanded)

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

GET/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/sor-state

Get Sor State

Read-only compact slice of the business's current SOR state for one extraction domain (design §11), so a WS2/WS4 extractor sees what already exists and its output dedups well at merge time.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
domainrequiredquerystring
x-internal-api-keyheaderstring | null

Responses

200Successful Response
application/jsonSuccessResponse_SorStateData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredSorStateData
SorStateData fields
FieldTypeDescription
domainrequiredstring
stateobject
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/stage-status

Record Stage Status

Project a workflow stage transition into ``onboarding_json.stages``.

The admin console's onboarding checklist reads the same shape whether the run was driven by the legacy in-process chain or the engine; ``executor`` and ``workflow_run_id`` are what distinguish them. The stage key is not validated against a fixed list so later workstreams (classification, enrichment) can journal new stages without a sor deploy.

The body is merged over the stage's existing entry, not substituted for it. ``/stages/{stage}`` and ``/stage-status`` are two calls, and keys the wrapper produced must survive the second one even if the engine doesn't echo them: ``finalize_website_onboarding`` finds the run by the ``website_id`` the website stage journaled, so dropping it would strand that stage at ``running`` forever.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonStageStatusBody
FieldTypeDescription
stagerequiredstringmin length 1
statusrequiredstring
errorstring | null
workflow_run_idstring | null
outcomeobject | null

Responses

200Successful Response
application/jsonSuccessResponse_StageStatusData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredStageStatusData
StageStatusData fields
FieldTypeDescription
stagerequiredstring
statusrequiredstring
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/stages/{stage}

Run Stage

Run one onboarding stage synchronously.

V1 of the engine-owned pipeline wraps the existing sor stage implementations rather than reimplementing them, so the legacy chain and the workflow drive identical code.

A stage-level failure returns **200** with ``status="failed"`` and the error: the workflow engine owns retry and fatality policy (merge/website are fatal, company_name/industries are not), so it must see the outcome rather than a 5xx it would blindly retry. Genuine infrastructure faults still 5xx.

Deliberately does not journal — the engine is the single writer of ``onboarding_json.stages`` via ``/stage-status``.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
stagerequiredpathstring
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonRunStageBody
FieldTypeDescription
extract_attempt_idstring (uuid) | null

Responses

200Successful Response
application/jsonSuccessResponse_RunStageData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredRunStageData
RunStageData fields
FieldTypeDescription
stagerequiredstring
statusrequiredstring
outcomeobject
errorstring | null
metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.

POST/api/v1/internal/workflow-engine/onboarding/runs/{run_id}/website-photos/auto-assign

Auto Assign Website Photos

Fill the logo/favicon ``website_photos`` slots — only where empty.

An admin (or earlier-run) assignment always wins: a filled slot is reported ``already_set`` and never clobbered (design §13 guardrails). The website is resolved through the run's business. A photo_id that isn't a live photo of that business is skipped as ``unknown_photo`` so a bad id can't wedge a slot with a dangling reference.

Parameters

NameInTypeDescription
run_idrequiredpathstring (uuid)
x-internal-api-keyheaderstring | null

Request bodyrequired

application/jsonAutoAssignWebsitePhotosBody
FieldTypeDescription
logo_fullstring (uuid) | null
faviconstring (uuid) | null

Responses

200Successful Response
application/jsonSuccessResponse_AutoAssignWebsitePhotosData_
FieldTypeDescription
request_idrequiredstring
successtruedefault true
datarequiredAutoAssignWebsitePhotosData
AutoAssignWebsitePhotosData fields
FieldTypeDescription
assignedobject
object fields

Map of string to string

skippedobject
object fields

Map of string to string

metadataResponseMetadata | null
ResponseMetadata fields

ResponseMetadata, expanded above.

metaResponseMeta | null
ResponseMeta fields

ResponseMeta, expanded above.

  • 400Bad request
  • 401Unauthorized
  • 403Forbidden
  • 404Not found
  • 422Validation error
  • 500Internal server error
  • 503Service unavailable

Error bodies: ErrorResponse. See Errors.