JJijibora Docs
docs.jijibora.online
On this page (38 sections)

Sokobora Sourcing Console API (fragment) — OpenAPI 1.1.0

<!-- GENERATED by scripts/render-platform-map-api-docs.mjs — do not hand-edit; edit apps/agent-bff/openapi/<spec>.json and re-run. --> Scope: The published reference for Sokobora Sourcing Console API (fragment). 26 paths — the measured spec-vs-implementation coverage lives in the complete API inventory. Status: rendered 2026-11-09 from the OpenAPI source for Sokobora Sourcing Console API (fragment) — regenerate with node scripts/render-platform-map-api-docs.mjs. See also: the OpenAPI spec index.

Servers

URLNotes
https://dev.agent.jijibora.onlineDokku DEV Agent BFF (cell: dev.jijibora.online)
https://uat.agent.jijibora.onlineDokku UAT Agent BFF
http://127.0.0.1:3030Local laptop only — not for public codegen

Tags

TagSummary
sokobora-gatewayUnified capability gateway (SOK-BFF-GATEWAY)
sokobora-metaReadiness and vertical packs
sokobora-supplierSupplier inventory, offerings, storefront, stats
sseSourcing SSE streams
sourcing-buyBuyer requirement / bid lifecycle
sourcing-sellSupplier quote / work-order lifecycle

Paths — 26 paths / 32 operations

MethodPathOperation IDSummary
GET/v1/soko/gatewaygetSokoboraGatewayCatalogUnified gateway catalog (Dokku public entry)
POST/v1/soko/gatewaypostSokoboraGatewayExecute capability via unified gateway (resolves integration)
GET/v1/soko/gateway/healthgetSokoboraGatewayHealthGateway health
GET/v1/soko/gateway/capabilitieslistSokoboraGatewayCapabilitiesList gateway capabilities
GET/v1/sokobora/gatewaygetSokoboraGatewayCatalogAliasAlias of GET /v1/soko/gateway
POST/v1/sokobora/gatewaypostSokoboraGatewayAliasAlias of POST /v1/soko/gateway
GET/v1/sokobora/readinessgetSokoboraReadinessSoft≠LIVE readiness (fail closed)
GET/v1/sokobora/packsgetSokoboraPacksVertical packs from SOVEREIGN_LOOKUPS
GET/v1/sokobora/suppliers/{orgId}/inventorylistSupplierInventoryList supplier inventory (goods + service availability)
PUT/v1/sokobora/suppliers/{orgId}/inventory/{itemId}upsertSupplierInventoryItemUpsert inventory stock or service availability
POST/v1/sokobora/suppliers/{orgId}/inventory/{itemId}/adjustadjustSupplierInventoryItemAdjust inventory by signed delta
GET/v1/sokobora/suppliers/{orgId}/offeringslistSupplierOfferingsList offerings (product\service)
POST/v1/sokobora/suppliers/{orgId}/offeringscreateSupplierOfferingCreate offering; optional Medusa publish
GET/v1/sokobora/suppliers/{orgId}/storefrontgetSupplierStorefrontMedusa storefront status (invent_refuse when bridge down)
GET/v1/sokobora/marketplace/listingslistSokoboraMarketplaceListingsPublic marketplace listings with search, paging, and cascading facets (Soft≠LIVE)
GET/v1/sokobora/marketplace/listings/{offeringId}getSokoboraMarketplaceListingItem profile: listing details, media, supplier link (claim SoR)
GET/v1/sokobora/suppliers/{orgId}/profilegetSupplierProfileSupplier profile + offerings preview (claim SoR). Path accepts opaque seller id (sp_…) or Soft org subject.
PUT/v1/sokobora/suppliers/{orgId}/profileputSupplierProfileReplace supplier profile fields (display_name, bio, media URLs caller-owned)
PATCH/v1/sokobora/suppliers/{orgId}/profilepatchSupplierProfilePartial update supplier profile (name/about/logo/banner/gallery)
POST/v1/sokobora/suppliers/{orgId}/mediauploadSupplierMediaUpload supplier/item image to MinIO; returns public URL (Soft Soft≠LIVE fail-closed)
PUT/v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/profileputSupplierOfferingProfileReplace offering/item profile (details, images, videos — no invented URLs)
PATCH/v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/profilepatchSupplierOfferingProfilePartial update offering/item profile
POST/v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/archivearchiveSupplierOfferingArchive offering — removed from public marketplace Soft≠LIVE
POST/v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/restorerestoreSupplierOfferingRestore archived offering to ACTIVE marketplace listing
GET/v1/sokobora/stats/summarygetSokoboraStatsSummaryScenario-class stats rollup (fail closed)
GET/v1/sourcing/events/streamsourcingEventsStreamGlobal sourcing SSE (Bearer auth)
GET/v1/sourcing/tenders/{tenderId}/streamsourcingTenderStreamPer-tender quote SSE
POST/v1/sourcing/requirements/{id}/cancelcancelSourcingRequirementCancel requirement
POST/v1/sourcing/bids/{id}/quorumevaluateSourcingBidQuorumLowest-bid quorum evaluate (id = requirementId)
PATCH/v1/sourcing/quotes/{id}patchSourcingQuoteAnnotate / adjust quote
POST/v1/sourcing/quotes/{id}/sign-convertsignConvertSourcingQuoteSign-convert quote to work order
POST/v1/sourcing/work-orders/{id}/advanceadvanceSourcingWorkOrderAdvance work-order FSM

Operations

GET /v1/soko/gateway

Summary: Unified gateway catalog (Dokku public entry)

Tags: sokobora-gateway Operation ID: getSokoboraGatewayCatalog Responses:

StatusMeaning
200base_url, gateway_url, dokku_cell, capabilities[]

POST /v1/soko/gateway

Summary: Execute capability via unified gateway (resolves integration)

Tags: sokobora-gateway Operation ID: postSokoboraGateway Request body:

Content type: application/json

FieldTypeNotes
capabilitystringe.g. marketplace.listings, payments.charge, settle, standing_orders
actionstringCapability action (list, charge, execute, …)
integrationstringauto (default) or explicit provider (mpesa, medusa, s117, …)
payloadobject
paramsobject
queryobject

Responses:

StatusMeaning
200ok + data + integration resolved
400bad capability/action/integration
401auth / FAPI
403RLS / APF deny
404unknown capability
422business / FAPI enforce off
502upstream fail-closed
503invent_refuse — engines down

GET /v1/soko/gateway/health

Summary: Gateway health

Tags: sokobora-gateway Operation ID: getSokoboraGatewayHealth Responses:

StatusMeaning
200health ok + capability_count

GET /v1/soko/gateway/capabilities

Summary: List gateway capabilities

Tags: sokobora-gateway Operation ID: listSokoboraGatewayCapabilities Responses:

StatusMeaning
200capabilities[]

GET /v1/sokobora/gateway

Summary: Alias of GET /v1/soko/gateway

Tags: sokobora-gateway Operation ID: getSokoboraGatewayCatalogAlias Responses:

StatusMeaning
200catalog

POST /v1/sokobora/gateway

Summary: Alias of POST /v1/soko/gateway

Tags: sokobora-gateway Operation ID: postSokoboraGatewayAlias Responses:

StatusMeaning
200ok
503invent_refuse

GET /v1/sokobora/readiness

Summary: Soft≠LIVE readiness (fail closed)

Tags: sokobora-meta Operation ID: getSokoboraReadiness Responses:

StatusMeaning
200sokobora_live true
503invent_refuse — engines down

GET /v1/sokobora/packs

Summary: Vertical packs from SOVEREIGN_LOOKUPS

Tags: sokobora-meta Operation ID: getSokoboraPacks Responses:

StatusMeaning
200packs
503KV missing / unavailable

GET /v1/sokobora/suppliers/{orgId}/inventory

Summary: List supplier inventory (goods + service availability)

Tags: sokobora-supplier Operation ID: listSupplierInventory

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring
offering_kindquerynostring enum: product, service

Responses:

StatusMeaning
200inventory items
503Surreal unavailable

PUT /v1/sokobora/suppliers/{orgId}/inventory/{itemId}

Summary: Upsert inventory stock or service availability

Tags: sokobora-supplier Operation ID: upsertSupplierInventoryItem

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring
itemIdpathyesstring

Responses:

StatusMeaning
200updated
201created
400validation
503Surreal unavailable

POST /v1/sokobora/suppliers/{orgId}/inventory/{itemId}/adjust

Summary: Adjust inventory by signed delta

Tags: sokobora-supplier Operation ID: adjustSupplierInventoryItem

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring
itemIdpathyesstring

Responses:

StatusMeaning
200adjusted
422insufficient quantity
503Surreal unavailable

GET /v1/sokobora/suppliers/{orgId}/offerings

Summary: List offerings (product|service)

Tags: sokobora-supplier Operation ID: listSupplierOfferings

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring

Responses:

StatusMeaning
200offerings
503Surreal unavailable

POST /v1/sokobora/suppliers/{orgId}/offerings

Summary: Create offering; optional Medusa publish

Tags: sokobora-supplier Operation ID: createSupplierOffering

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring

Responses:

StatusMeaning
201created
400validation
503Surreal/Medusa unavailable

GET /v1/sokobora/suppliers/{orgId}/storefront

Summary: Medusa storefront status (invent_refuse when bridge down)

Tags: sokobora-supplier Operation ID: getSupplierStorefront

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring

Responses:

StatusMeaning
200medusa ok
503invent_refuse — Medusa bridge down

GET /v1/sokobora/marketplace/listings

Summary: Public marketplace listings with search, paging, and cascading facets (Soft≠LIVE)

Tags: sokobora-supplier Operation ID: listSokoboraMarketplaceListings

Parameters:

NameInRequiredTypeNotes
qquerynostringFree-text search
limitquerynoint
offsetquerynoint
pagequerynoint
kindquerynostring enum: product, service
verticalquerynostringIndustry key id (e.g. agriculture)
category_idquerynostringCategory id (e.g. agri.maize) — not display name
categoryquerynostringAlias of category_id (legacy)
unitquerynostring
channelquerynostring
sellerquerynostringOpaque seller record id (sp_…). Preferred public filter.
org_idquerynostringLegacy Soft subject — resolved to seller public_id; do not use in new URLs
has_mediaquerynoboolean

Responses:

StatusMeaning
200listings + page/total/has_more + facets + filters
503Surreal unavailable — invent_refuse

GET /v1/sokobora/marketplace/listings/{offeringId}

Summary: Item profile: listing details, media, supplier link (claim SoR)

Tags: sokobora-supplier Operation ID: getSokoboraMarketplaceListing

Parameters:

NameInRequiredTypeNotes
offeringIdpathyesstring

Responses:

StatusMeaning
200listing + links.supplier_profile
404not found
503Surreal unavailable

GET /v1/sokobora/suppliers/{orgId}/profile

Summary: Supplier profile + offerings preview (claim SoR). Path accepts opaque seller id (sp_…) or Soft org subject.

Tags: sokobora-supplier Operation ID: getSupplierProfile

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstringPrefer sp_… public seller id; Soft org: subject accepted for owner writes
limitquerynoint
pagequerynoint
qquerynostring

Responses:

StatusMeaning
200profile (org_id redacted unless X-Org-Id owner) + editable + offerings_preview + catalog_path?seller=sp_…
404seller/profile not found
503Surreal unavailable

PUT /v1/sokobora/suppliers/{orgId}/profile

Summary: Replace supplier profile fields (display_name, bio, media URLs caller-owned)

Tags: sokobora-supplier Operation ID: putSupplierProfile

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring

Responses:

StatusMeaning
200updated
400validation
503Surreal unavailable

PATCH /v1/sokobora/suppliers/{orgId}/profile

Summary: Partial update supplier profile (name/about/logo/banner/gallery)

Tags: sokobora-supplier Operation ID: patchSupplierProfile

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring

Responses:

StatusMeaning
200updated
400validation
503Surreal unavailable

POST /v1/sokobora/suppliers/{orgId}/media

Summary: Upload supplier/item image to MinIO; returns public URL (Soft Soft≠LIVE fail-closed)

Tags: sokobora-supplier Operation ID: uploadSupplierMedia

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring

Request body:

Content type: application/json

FieldTypeNotes
data_urlstringdata:image/…;base64,…
base64string
content_typestring enum: image/jpeg, image/png, image/webp, image/gif
rolestringlogo\banner\gallery\primary\image
offering_idstringWhen uploading for an item profile
urlstringExisting http(s) URL passthrough, or data: URL

Responses:

StatusMeaning
201{ data: { url, stored, role, kind } } — url is http(s) or /v1/profile-assets/…
400invalid body / mime
413image too large
503MinIO / object storage invent_refuse

PUT /v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/profile

Summary: Replace offering/item profile (details, images, videos — no invented URLs)

Tags: sokobora-supplier Operation ID: putSupplierOfferingProfile

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring
offeringIdpathyesstring

Responses:

StatusMeaning
200updated
404offering not found
503Surreal unavailable

PATCH /v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/profile

Summary: Partial update offering/item profile

Tags: sokobora-supplier Operation ID: patchSupplierOfferingProfile

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring
offeringIdpathyesstring

Responses:

StatusMeaning
200updated
404offering not found
503Surreal unavailable

POST /v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/archive

Summary: Archive offering — removed from public marketplace Soft≠LIVE

Tags: sokobora-supplier Operation ID: archiveSupplierOffering

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring
offeringIdpathyesstring

Responses:

StatusMeaning
200archived
403org mismatch
404not found
503Surreal unavailable

POST /v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/restore

Summary: Restore archived offering to ACTIVE marketplace listing

Tags: sokobora-supplier Operation ID: restoreSupplierOffering

Parameters:

NameInRequiredTypeNotes
orgIdpathyesstring
offeringIdpathyesstring

Responses:

StatusMeaning
200restored
403org mismatch
404not found
503Surreal unavailable

GET /v1/sokobora/stats/summary

Summary: Scenario-class stats rollup (fail closed)

Tags: sokobora-supplier Operation ID: getSokoboraStatsSummary

Parameters:

NameInRequiredTypeNotes
org_idquerynostring
is_testquerynoboolean

Responses:

StatusMeaning
200summary
503engines down — invent_refuse

GET /v1/sourcing/events/stream

Summary: Global sourcing SSE (Bearer auth)

Tags: sse Operation ID: sourcingEventsStream Responses:

StatusMeaning
200text/event-stream
503NATS unavailable

GET /v1/sourcing/tenders/{tenderId}/stream

Summary: Per-tender quote SSE

Tags: sse Operation ID: sourcingTenderStream

Parameters:

NameInRequiredTypeNotes
tenderIdpathyesstring

Responses:

StatusMeaning
200text/event-stream
400token query forbidden or missing tenderId
503NATS unavailable

POST /v1/sourcing/requirements/{id}/cancel

Summary: Cancel requirement

Tags: sourcing-buy Operation ID: cancelSourcingRequirement

Parameters:

NameInRequiredTypeNotes
idpathyesstring

Responses:

StatusMeaning
200cancelled
404not found

POST /v1/sourcing/bids/{id}/quorum

Summary: Lowest-bid quorum evaluate (id = requirementId)

Tags: sourcing-buy Operation ID: evaluateSourcingBidQuorum

Parameters:

NameInRequiredTypeNotes
idpathyesstring

Responses:

StatusMeaning
200winner selected
422no pending bids

PATCH /v1/sourcing/quotes/{id}

Summary: Annotate / adjust quote

Tags: sourcing-sell Operation ID: patchSourcingQuote

Parameters:

NameInRequiredTypeNotes
idpathyesstring

Responses:

StatusMeaning
200updated
404not found

POST /v1/sourcing/quotes/{id}/sign-convert

Summary: Sign-convert quote to work order

Tags: sourcing-sell Operation ID: signConvertSourcingQuote

Parameters:

NameInRequiredTypeNotes
idpathyesstring

Responses:

StatusMeaning
200work order created
404not found

POST /v1/sourcing/work-orders/{id}/advance

Summary: Advance work-order FSM

Tags: sourcing-sell Operation ID: advanceSourcingWorkOrder

Parameters:

NameInRequiredTypeNotes
idpathyesstring

Responses:

StatusMeaning
200advanced
404not found

Full specification — verbatim source of truth

{
  "openapi": "3.1.0",
  "info": {
    "title": "Sokobora Sourcing Console API (fragment)",
    "version": "1.1.0",
    "description": "Public Dokku hosts: https://dev.agent.jijibora.online (DEV cell host: dev.jijibora.online), https://uat.agent.jijibora.online (UAT). Unified gateway: POST /v1/soko/gateway (prefer for agents). Soft≠LIVE: never invent sokobora_live. See docs/sokobora/UNIFIED_GATEWAY_DESIGN.md and docs/ops/SOKOBORA_DOKKU_LIVE_RUNBOOK.md"
  },
  "servers": [
    {
      "url": "https://dev.agent.jijibora.online",
      "description": "Dokku DEV Agent BFF (cell: dev.jijibora.online)"
    },
    {
      "url": "https://uat.agent.jijibora.online",
      "description": "Dokku UAT Agent BFF"
    },
    {
      "url": "http://127.0.0.1:3030",
      "description": "Local laptop only — not for public codegen"
    }
  ],
  "tags": [
    {
      "name": "sokobora-gateway",
      "description": "Unified capability gateway (SOK-BFF-GATEWAY)"
    },
    {
      "name": "sokobora-meta",
      "description": "Readiness and vertical packs"
    },
    {
      "name": "sokobora-supplier",
      "description": "Supplier inventory, offerings, storefront, stats"
    },
    {
      "name": "sse",
      "description": "Sourcing SSE streams"
    },
    {
      "name": "sourcing-buy",
      "description": "Buyer requirement / bid lifecycle"
    },
    {
      "name": "sourcing-sell",
      "description": "Supplier quote / work-order lifecycle"
    }
  ],
  "paths": {
    "/v1/soko/gateway": {
      "get": {
        "tags": [
          "sokobora-gateway"
        ],
        "summary": "Unified gateway catalog (Dokku public entry)",
        "operationId": "getSokoboraGatewayCatalog",
        "responses": {
          "200": {
            "description": "base_url, gateway_url, dokku_cell, capabilities[]"
          }
        }
      },
      "post": {
        "tags": [
          "sokobora-gateway"
        ],
        "summary": "Execute capability via unified gateway (resolves integration)",
        "operationId": "postSokoboraGateway",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "capability",
                  "action"
                ],
                "properties": {
                  "capability": {
                    "type": "string",
                    "description": "e.g. marketplace.listings, payments.charge, settle, standing_orders"
                  },
                  "action": {
                    "type": "string",
                    "description": "Capability action (list, charge, execute, …)"
                  },
                  "integration": {
                    "type": "string",
                    "description": "auto (default) or explicit provider (mpesa, medusa, s117, …)"
                  },
                  "payload": {
                    "type": "object"
                  },
                  "params": {
                    "type": "object"
                  },
                  "query": {
                    "type": "object"
                  }
                }
              },
              "example": {
                "capability": "marketplace.listings",
                "action": "list",
                "integration": "auto",
                "query": {
                  "limit": 24
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ok + data + integration resolved"
          },
          "400": {
            "description": "bad capability/action/integration"
          },
          "401": {
            "description": "auth / FAPI"
          },
          "403": {
            "description": "RLS / APF deny"
          },
          "404": {
            "description": "unknown capability"
          },
          "422": {
            "description": "business / FAPI enforce off"
          },
          "502": {
            "description": "upstream fail-closed"
          },
          "503": {
            "description": "invent_refuse — engines down"
          }
        }
      }
    },
    "/v1/soko/gateway/health": {
      "get": {
        "tags": [
          "sokobora-gateway"
        ],
        "summary": "Gateway health",
        "operationId": "getSokoboraGatewayHealth",
        "responses": {
          "200": {
            "description": "health ok + capability_count"
          }
        }
      }
    },
    "/v1/soko/gateway/capabilities": {
      "get": {
        "tags": [
          "sokobora-gateway"
        ],
        "summary": "List gateway capabilities",
        "operationId": "listSokoboraGatewayCapabilities",
        "responses": {
          "200": {
            "description": "capabilities[]"
          }
        }
      }
    },
    "/v1/sokobora/gateway": {
      "get": {
        "tags": [
          "sokobora-gateway"
        ],
        "summary": "Alias of GET /v1/soko/gateway",
        "operationId": "getSokoboraGatewayCatalogAlias",
        "responses": {
          "200": {
            "description": "catalog"
          }
        }
      },
      "post": {
        "tags": [
          "sokobora-gateway"
        ],
        "summary": "Alias of POST /v1/soko/gateway",
        "operationId": "postSokoboraGatewayAlias",
        "responses": {
          "200": {
            "description": "ok"
          },
          "503": {
            "description": "invent_refuse"
          }
        }
      }
    },
    "/v1/sokobora/readiness": {
      "get": {
        "tags": [
          "sokobora-meta"
        ],
        "summary": "Soft≠LIVE readiness (fail closed)",
        "operationId": "getSokoboraReadiness",
        "responses": {
          "200": {
            "description": "sokobora_live true"
          },
          "503": {
            "description": "invent_refuse — engines down"
          }
        }
      }
    },
    "/v1/sokobora/packs": {
      "get": {
        "tags": [
          "sokobora-meta"
        ],
        "summary": "Vertical packs from SOVEREIGN_LOOKUPS",
        "operationId": "getSokoboraPacks",
        "responses": {
          "200": {
            "description": "packs"
          },
          "503": {
            "description": "KV missing / unavailable"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/inventory": {
      "get": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "List supplier inventory (goods + service availability)",
        "operationId": "listSupplierInventory",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offering_kind",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "product",
                "service"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "inventory items"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/inventory/{itemId}": {
      "put": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Upsert inventory stock or service availability",
        "operationId": "upsertSupplierInventoryItem",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "itemId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "updated"
          },
          "201": {
            "description": "created"
          },
          "400": {
            "description": "validation"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/inventory/{itemId}/adjust": {
      "post": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Adjust inventory by signed delta",
        "operationId": "adjustSupplierInventoryItem",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "itemId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "adjusted"
          },
          "422": {
            "description": "insufficient quantity"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/offerings": {
      "get": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "List offerings (product|service)",
        "operationId": "listSupplierOfferings",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "offerings"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      },
      "post": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Create offering; optional Medusa publish",
        "operationId": "createSupplierOffering",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "created"
          },
          "400": {
            "description": "validation"
          },
          "503": {
            "description": "Surreal/Medusa unavailable"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/storefront": {
      "get": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Medusa storefront status (invent_refuse when bridge down)",
        "operationId": "getSupplierStorefront",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "medusa ok"
          },
          "503": {
            "description": "invent_refuse — Medusa bridge down"
          }
        }
      }
    },
    "/v1/sokobora/marketplace/listings": {
      "get": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Public marketplace listings with search, paging, and cascading facets (Soft≠LIVE)",
        "operationId": "listSokoboraMarketplaceListings",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Free-text search"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 24
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "kind",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "product",
                "service"
              ]
            }
          },
          {
            "name": "vertical",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Industry key id (e.g. agriculture)"
          },
          {
            "name": "category_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Category id (e.g. agri.maize) — not display name"
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Alias of category_id (legacy)"
          },
          {
            "name": "unit",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "channel",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "seller",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque seller record id (sp_…). Preferred public filter."
          },
          {
            "name": "org_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Legacy Soft subject — resolved to seller public_id; do not use in new URLs"
          },
          {
            "name": "has_media",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "listings + page/total/has_more + facets + filters"
          },
          "503": {
            "description": "Surreal unavailable — invent_refuse"
          }
        }
      }
    },
    "/v1/sokobora/marketplace/listings/{offeringId}": {
      "get": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Item profile: listing details, media, supplier link (claim SoR)",
        "operationId": "getSokoboraMarketplaceListing",
        "parameters": [
          {
            "name": "offeringId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "listing + links.supplier_profile"
          },
          "404": {
            "description": "not found"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/profile": {
      "get": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Supplier profile + offerings preview (claim SoR). Path accepts opaque seller id (sp_…) or Soft org subject.",
        "operationId": "getSupplierProfile",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefer sp_… public seller id; Soft org: subject accepted for owner writes"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "profile (org_id redacted unless X-Org-Id owner) + editable + offerings_preview + catalog_path?seller=sp_…"
          },
          "404": {
            "description": "seller/profile not found"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      },
      "put": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Replace supplier profile fields (display_name, bio, media URLs caller-owned)",
        "operationId": "putSupplierProfile",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "updated"
          },
          "400": {
            "description": "validation"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Partial update supplier profile (name/about/logo/banner/gallery)",
        "operationId": "patchSupplierProfile",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "updated"
          },
          "400": {
            "description": "validation"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/media": {
      "post": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Upload supplier/item image to MinIO; returns public URL (Soft Soft≠LIVE fail-closed)",
        "operationId": "uploadSupplierMedia",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data_url": {
                    "type": "string",
                    "description": "data:image/…;base64,…"
                  },
                  "base64": {
                    "type": "string"
                  },
                  "content_type": {
                    "type": "string",
                    "enum": [
                      "image/jpeg",
                      "image/png",
                      "image/webp",
                      "image/gif"
                    ]
                  },
                  "role": {
                    "type": "string",
                    "description": "logo|banner|gallery|primary|image"
                  },
                  "offering_id": {
                    "type": "string",
                    "description": "When uploading for an item profile"
                  },
                  "url": {
                    "type": "string",
                    "description": "Existing http(s) URL passthrough, or data: URL"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "{ data: { url, stored, role, kind } } — url is http(s) or /v1/profile-assets/…"
          },
          "400": {
            "description": "invalid body / mime"
          },
          "413": {
            "description": "image too large"
          },
          "503": {
            "description": "MinIO / object storage invent_refuse"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/profile": {
      "put": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Replace offering/item profile (details, images, videos — no invented URLs)",
        "operationId": "putSupplierOfferingProfile",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offeringId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "updated"
          },
          "404": {
            "description": "offering not found"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      },
      "patch": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Partial update offering/item profile",
        "operationId": "patchSupplierOfferingProfile",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offeringId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "updated"
          },
          "404": {
            "description": "offering not found"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/archive": {
      "post": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Archive offering — removed from public marketplace Soft≠LIVE",
        "operationId": "archiveSupplierOffering",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offeringId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "archived"
          },
          "403": {
            "description": "org mismatch"
          },
          "404": {
            "description": "not found"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      }
    },
    "/v1/sokobora/suppliers/{orgId}/offerings/{offeringId}/restore": {
      "post": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Restore archived offering to ACTIVE marketplace listing",
        "operationId": "restoreSupplierOffering",
        "parameters": [
          {
            "name": "orgId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "offeringId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "restored"
          },
          "403": {
            "description": "org mismatch"
          },
          "404": {
            "description": "not found"
          },
          "503": {
            "description": "Surreal unavailable"
          }
        }
      }
    },
    "/v1/sokobora/stats/summary": {
      "get": {
        "tags": [
          "sokobora-supplier"
        ],
        "summary": "Scenario-class stats rollup (fail closed)",
        "operationId": "getSokoboraStatsSummary",
        "parameters": [
          {
            "name": "org_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "is_test",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "summary"
          },
          "503": {
            "description": "engines down — invent_refuse"
          }
        }
      }
    },
    "/v1/sourcing/events/stream": {
      "get": {
        "tags": [
          "sse"
        ],
        "summary": "Global sourcing SSE (Bearer auth)",
        "operationId": "sourcingEventsStream",
        "responses": {
          "200": {
            "description": "text/event-stream"
          },
          "503": {
            "description": "NATS unavailable"
          }
        }
      }
    },
    "/v1/sourcing/tenders/{tenderId}/stream": {
      "get": {
        "tags": [
          "sse"
        ],
        "summary": "Per-tender quote SSE",
        "operationId": "sourcingTenderStream",
        "parameters": [
          {
            "name": "tenderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream"
          },
          "400": {
            "description": "token query forbidden or missing tenderId"
          },
          "503": {
            "description": "NATS unavailable"
          }
        }
      }
    },
    "/v1/sourcing/requirements/{id}/cancel": {
      "post": {
        "tags": [
          "sourcing-buy"
        ],
        "summary": "Cancel requirement",
        "operationId": "cancelSourcingRequirement",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "cancelled"
          },
          "404": {
            "description": "not found"
          }
        }
      }
    },
    "/v1/sourcing/bids/{id}/quorum": {
      "post": {
        "tags": [
          "sourcing-buy"
        ],
        "summary": "Lowest-bid quorum evaluate (id = requirementId)",
        "operationId": "evaluateSourcingBidQuorum",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "winner selected"
          },
          "422": {
            "description": "no pending bids"
          }
        }
      }
    },
    "/v1/sourcing/quotes/{id}": {
      "patch": {
        "tags": [
          "sourcing-sell"
        ],
        "summary": "Annotate / adjust quote",
        "operationId": "patchSourcingQuote",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "updated"
          },
          "404": {
            "description": "not found"
          }
        }
      }
    },
    "/v1/sourcing/quotes/{id}/sign-convert": {
      "post": {
        "tags": [
          "sourcing-sell"
        ],
        "summary": "Sign-convert quote to work order",
        "operationId": "signConvertSourcingQuote",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "work order created"
          },
          "404": {
            "description": "not found"
          }
        }
      }
    },
    "/v1/sourcing/work-orders/{id}/advance": {
      "post": {
        "tags": [
          "sourcing-sell"
        ],
        "summary": "Advance work-order FSM",
        "operationId": "advanceSourcingWorkOrder",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "advanced"
          },
          "404": {
            "description": "not found"
          }
        }
      }
    }
  }
}