"description":"Read API over the procurement-ingest pipelines (work orders and purchase orders). The outbound SHOC work-order webhook feed is documented under **webhooks** below.\n\nData endpoints use AWS IAM SigV4; the `/docs` and `/openapi.json` routes use a shared token. Listings are unordered, cursor-paginated scans. Endpoints tagged **x-planned** are phase 2 and currently answer `501`.\n\nThis API replaces SHOC's retired SyncController DynamoDB scan as the reconciliation and backfill path. Full detail: the repo README and `docs/shoc-webhook-contract.md`."
"summary":"List work orders (unordered, paginated)",
"parameters":[
{
"$ref":"#/components/parameters/Limit"
},
{
"$ref":"#/components/parameters/Cursor"
}
],
"responses":{
"200":{
"description":"One page of work orders.",
"content":{
"application/json":{
"schema":{
"type":"object",
"required":["items","next_cursor"],
"properties":{
"items":{
"type":"array",
"items":{
"$ref":"#/components/schemas/WorkOrder"
}
},
"next_cursor":{
"$ref":"#/components/schemas/NextCursor"
}
}
}
}
}
},
"400":{
"$ref":"#/components/responses/BadRequest"
},
"403":{
"$ref":"#/components/responses/Forbidden"
}
}
}
},
"/work-orders/{workOrderId}":{
"get":{
"operationId":"getWorkOrder",
"summary":"Get one work order",
"parameters":[
{
"$ref":"#/components/parameters/WorkOrderId"
}
],
"responses":{
"200":{
"description":"The work order.",
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/WorkOrder"
}
}
}
},
"403":{
"$ref":"#/components/responses/Forbidden"
},
"404":{
"$ref":"#/components/responses/NotFound"
}
}
},
"patch":{
"x-planned":true,
"operationId":"patchWorkOrder",
"summary":"PLANNED (phase 2): update dispatch fields on a work order",
"description":"Not implemented - returns 501. Phase-2 write-back for SHOC dispatch workflow (status/assignment). Writes will stamp `write_origin: shoc-write-api` so the outbound webhook never echoes SHOC's own writes back at it. Ships with its own IAM diff and cross-family review.",
"responses":{
"501":{
"$ref":"#/components/responses/NotImplemented"
}
}
}
},
"/work-orders/{workOrderId}/comments":{
"get":{
"operationId":"listWorkOrderComments",
"summary":"List comments/events for a work order (paginated)",
"summary":"PLANNED (phase 2): append a SHOC-authored comment",
"description":"Not implemented - returns 501. Phase-2 write-back: SHOC dispatch notes land in WorkOrderComments with `write_origin: shoc-write-api` (append-only; no field conflicts with the email pipeline). Ships with its own IAM diff and cross-family review.",
"description":"Browser convenience: the docs token as a query parameter (browsers can't set headers on navigation). Prefer the X-Auth-Token header from tooling."
}
],
"responses":{
"200":{
"description":"Self-contained HTML reference page.",
"content":{
"text/html":{}
}
},
"401":{
"$ref":"#/components/responses/Unauthorized"
}
}
}
},
"/openapi.json":{
"get":{
"operationId":"getOpenApiSpec",
"summary":"This spec (token-gated)",
"security":[
{
"docsToken":[]
}
],
"responses":{
"200":{
"description":"The OpenAPI 3.1 document.",
"content":{
"application/json":{}
}
},
"401":{
"$ref":"#/components/responses/Unauthorized"
}
}
}
}
},
"webhooks":{
"work_order.created":{
"post":{
"summary":"Outbound: a work order was created",
"description":"Sent by `workorder-shoc-emitter` (seahaven-prod) to the configured SHOC endpoint. Full contract incl. HMAC verification, ordering, and retry semantics: `docs/shoc-webhook-contract.md` (Rev 2026-07-23). Requests carry `X-SH-Timestamp`, `X-SH-Key-Id`, and `X-SH-Signature: v1=hex(HMAC_SHA256(secret, \"{timestamp}.{raw_body}\"))`; verify over the raw body, constant-time, +/-300s window, fail closed.",
"description":"Delivered. Respond fast (<10s); accept-and-enqueue if processing is slow. 429/5xx/timeouts are retried in order for 24h; other 4xx park immediately."
}
}
}
},
"work_order.updated":{
"post":{
"summary":"Outbound: a work order changed",
"description":"Same envelope and semantics as work_order.created; `data` is the full current state, not a diff.",
"summary":"Outbound: a comment/event record was ingested",
"description":"One per source email (comments, updates, and cancellation event records). Dedupe on `delivery_id` or `data.comment_id`. May occasionally arrive before the work order's created event - upsert a skeleton work order and let the state event backfill it.",
"description":"AWS IAM SigV4 (service execute-api, region us-east-1). Cross-account callers must be allowed by the API resource policy; Postman signs natively via Authorization type 'AWS Signature'."
"description":"Display timestamp (comment time when the source email carried one)."
},
"ingested_at":{
"type":["string","null"],
"description":"When the pipeline wrote the row; ISO 8601 with UTC offset."
},
"source_email_s3_key":{
"type":["string","null"]
}
},
"additionalProperties":true
},
"PurchaseOrder":{
"type":"object",
"description":"Mirrors the purchase-orders DynamoDB item (PK po_number). Shape follows the Coupa extraction schema; older records may lack newer fields.",
"required":["po_number"],
"properties":{
"po_number":{
"type":"string"
},
"po_status":{
"type":["string","null"]
},
"email_type":{
"type":["string","null"]
},
"source_system":{
"type":["string","null"]
},
"submitted_by":{
"type":["string","null"]
},
"on_behalf_of":{
"type":["string","null"]
},
"order_date":{
"type":["string","null"]
},
"revision_date":{
"type":["string","null"]
},
"payment_terms":{
"type":["string","null"]
},
"requisition_number":{
"type":["string","null"]
},
"department":{
"type":["string","null"]
},
"view_order_url":{
"type":["string","null"]
},
"supplier":{
"type":["object","null"],
"properties":{
"name":{
"type":["string","null"]
}
},
"additionalProperties":true
},
"site_code":{
"type":["string","null"]
},
"ship_to":{
"type":["object","null"],
"properties":{
"name":{
"type":["string","null"]
},
"address":{
"type":["string","null"]
},
"street":{
"type":["string","null"]
},
"city":{
"type":["string","null"]
},
"state":{
"type":["string","null"]
},
"zip":{
"type":["string","null"]
},
"location_code":{
"type":["string","null"]
},
"attn":{
"type":["string","null"]
}
},
"additionalProperties":true
},
"total_amount":{
"type":["number","null"],
"description":"Stored as Decimal; serialized as a JSON number."
},
"currency":{
"type":["string","null"]
},
"fiscal_year":{
"type":["string","null"]
},
"trade":{
"type":["string","null"]
},
"coupa_category":{
"type":["string","null"]
},
"line_items":{
"type":["array","null"],
"items":{
"type":"object",
"properties":{
"description":{
"type":["string","null"]
},
"quantity":{
"type":["number","null"]
},
"unit":{
"type":["string","null"]
},
"price":{
"type":["number","null"]
},
"amount":{
"type":["number","null"]
},
"currency":{
"type":["string","null"]
},
"need_by":{
"type":["string","null"]
},
"category":{
"type":["string","null"]
},
"account_code":{
"type":["string","null"]
},
"period":{
"type":["string","null"]
}
},
"additionalProperties":true
}
},
"cancelled_at":{
"type":["string","null"]
},
"processed_at":{
"type":["string","null"]
},
"raw_s3_key":{
"type":["string","null"]
},
"data_source":{
"type":["string","null"]
}
},
"additionalProperties":true
},
"VerifiedSite":{
"type":"object",
"description":"Mirrors the verified-sites DynamoDB item (PK siteCode), maintained by the PO site extractor.",
"required":["siteCode"],
"properties":{
"siteCode":{
"type":"string"
},
"address":{
"type":["string","null"]
},
"city":{
"type":["string","null"]
},
"state":{
"type":["string","null"]
},
"zip":{
"type":["string","null"]
},
"fullAddress":{
"type":["string","null"]
},
"locationCode":{
"type":["string","null"]
},
"poCount":{
"type":["integer","null"],
"description":"Count of POs that referenced this site."
},
"sourcePOs":{
"type":["array","null"],
"items":{
"type":"string"
},
"description":"PO numbers that referenced this site (string set; serialized sorted)."
"description":"Forward-compat (phase 2): present on records written through the write-back API; the emitter skips those, so receivers should tolerate but never see it."
}
}
},
"CommentEventData":{
"type":"object",
"description":"Contract section 4.2. Same fields as WorkOrderComment minus source_email_s3_key.",