openapi: 3.0.0 info: title: Aura Historia API Reference description: "## Overview\n\nThe Aura Historia API powers the Aura Historia antiques platform and its partner-facing integrations.\n\ It exposes product discovery, listing source discovery, personalization, partner onboarding, and integration\nworkflows\ \ on top of Aura Historia's serverless AWS platform.\n\nThis reference is designed for two audiences:\n- **Internal developers**\ \ building Aura Historia product-listings, operational tooling, and backoffice workflows\n- **External partners and integrators**\ \ synchronizing inventory, consuming platform data, or\n integrating with delegated access\n\n## Core API domains\n\n\ - **ProductListings and listing-sources** — search, retrieve, and explore product-listings, related product-listings,\ \ product\n history, and listing source data\n- **Personalization** — manage watchlists, saved search filters, and user\ \ notifications\n- **Partner workflows** — submit partnership applications, maintain partnerships, ingest catalog data\n\ \ in batches, and receive WooCommerce webhooks\n- **Identity and access** — manage user accounts, Aura Historia access\ \ tokens, and OAuth 2.0\n clients and token flows\n- **Billing** — create Stripe checkout, billing-portal, and subscription-management\ \ sessions\n\n## Authentication model\n\nThe API uses more than one authentication scheme depending on the route:\n\n\ - **`BearerAuth`** — Cognito **access** JWT bearer tokens for authenticated user, admin, and\n partner-user workflows.\ \ Cognito ID tokens are not accepted as API credentials.\n- **`AccessTokenAuth`** — Aura Historia opaque bearer access\ \ tokens created via\n `/api/v1/me/access-tokens` or OAuth 2.0, primarily intended for partner automations and server-to-server\n\ \ ingestion scenarios.\n\nWhen a route lists multiple security schemes, any one of the listed schemes may be accepted.\n\ Some read endpoints can also be called without authentication, while a valid user token may enrich\nthe response with\ \ personalized state such as watchlist, notification, or search-filter metadata.\n\n## Data and response conventions\n\ \n- **PATCH:** an omitted request member remains unchanged. A documented nullable PATCH member\n accepts `null` to clear\ \ its value; `null` for any other member returns `400 BAD_BODY_VALUE`.\n Use `[]`, not `null`, to replace a non-null\ \ collection with an empty collection. Empty HTTP\n bodies are invalid, `{}` is a valid object-PATCH no-op, and the partner-product\ \ PATCH `[]`\n remains a valid empty batch. Responses may omit absent optional values.\n- Product detail, watchlist,\ \ and saved-search match reads accept optional **`language`** and\n **`currency`** parameters. Currency defaults to `EUR`.\ \ Detail pricing contains the seller's source\n amounts, converted display amounts, and FX valuation metadata. Active\ \ product-listings use the latest persisted\n snapshot; sold product-listings use their immutable sale snapshot. Product\ \ history preserves immutable source values and accepts optional `currency` for historical FX display projections.\n History text is not localized.\n- Request-wide errors are returned as **`application/problem+json`**\ \ using a consistent RFC 9457-style structure\n with `status`, `title`, `error`, optional `source`, and optional `detail`\n\ - Many list and search endpoints use **cursor-based pagination** via `searchAfter`\n- Origin API responses include\ \ server-generated `X-Request-Id` and `X-Correlation-Id` headers. Clients may send `X-Correlation-Id` to preserve a trace\ \ only when it is a 1–128-character ASCII value containing letters, digits, `.`, `_`, or `-`; invalid values are replaced.\ \ Both headers are CORS-exposed; CloudFront removes them from viewer responses on the six cache-enabled discovery behaviors so shared cache hits cannot replay origin IDs.\n- Requests are limited to 1 MiB and time out after 30 seconds.\n- `POST /api/v1/webhooks/loops` is limited to 64 KiB and has a 10-second processing budget; it requires a valid Loops signature but no Aura bearer.\n- `GET /api/v1/health` is a\ \ process liveness check. `GET /api/v1/ready` returns `204` only when the configured PostgreSQL and OpenSearch dependencies are\ \ reachable; it otherwise returns `503`.\n- WooCommerce webhook ingestion responds with **`204 No Content`** after\ \ signed validation. A mapped raw-capture command receives `204` only after confirmed shared FIFO admission; authorized ignored create/update status events are no-op `204`. Queue admission is not raw capture, provider receipt persistence, canonical normalization, or search visibility. Capture conflicts are handled by the consumer, not returned synchronously; existing partner Product batch writes remain synchronous.\n\n## Environment\ \ endpoints\n\n- **Development:** `https://api.stage.aura-historia.com`\n- **Production:** `https://api.aura-historia.com`\n\ \n## Notes for integrators\n\n- Treat Aura Historia identifiers such as `listingSourceId`, `productListingId`, `eventId`,\ \ `userSearchFilterId`,\n and `partnershipApplicationId` as opaque values\n- For partner product ingestion, `sourceListingId`\ \ is the partner-controlled identifier and should\n remain stable within a listing source\n- Endpoints marked `deprecated`\ \ or `x-disabled` are retained for reference only and should not be\n used for new integrations\n" version: 1.0.0 contact: name: Aura-Historia Team url: https://aura-historia.com/ license: name: License url: https://github.com/aura-historia/backend/blob/develop/LICENSE servers: - url: https://api.stage.aura-historia.com description: Development environment - url: https://api.aura-historia.com description: Production environment paths: /api/v1/health: get: summary: Check process liveness description: Returns the fixed `ok` response without checking dependencies. operationId: getHealth tags: [Operations] security: [] responses: "200": description: The process is alive. content: text/plain: schema: { type: string } example: "ok\n" /api/v1/ready: get: summary: Check service readiness description: Returns no diagnostic body when readiness fails. operationId: getReadiness tags: [Operations] security: [] responses: "204": description: The readiness check succeeded. "503": description: The readiness check failed or timed out; no diagnostic body is returned. /api/v1/auctions: get: summary: List public Auctions operationId: listAuctions tags: [Auctions] parameters: - { name: listingSourceId, in: query, schema: { type: string } } - { name: format, in: query, schema: { type: string, enum: [LIVE, TIMED] }, } - { name: reportedStatus, in: query, schema: { type: string, enum: [SCHEDULED, IN_PROGRESS, ENDED, POSTPONED, CANCELLED], }, } - { name: timeRole, in: query, schema: { type: string, enum: [ BIDDING_OPENS, LIVE_STARTS, LOTS_BEGIN_CLOSING, SCHEDULED_END, ], }, } - { name: from, in: query, schema: { type: string, format: date-time } } - { name: to, in: query, schema: { type: string, format: date-time } } - name: sort in: query description: "`created` sorts by creation time; `scheduled` requires `timeRole` and sorts on that role's instant, with missing instants last when no window is specified." schema: { type: string, enum: [created, scheduled], default: created } - name: order in: query description: Defaults to `desc` for created and `asc` for scheduled. schema: { type: string, enum: [asc, desc] } - { name: pageSize, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 21 }, } - name: searchAfter in: query description: Complete returned JSON cursor. Its scope must match the source, format, reported-status, exact-time filters, sort and order of this request. schema: { type: string } responses: "200": description: "Bounded Auction directory, newest-created-first by default. Scheduled order uses the chosen role instant, with Auction ID as the final tie-breaker. Anonymous successful 200 responses without Authorization use `public, max-age=0, s-maxage=60, stale-if-error=0`; requests with any Authorization header and all non-200 responses use `private, no-store`." content: application/json: schema: $ref: "#/components/schemas/PublicAuctionDirectoryData" "400": description: "Invalid ID, filter, cursor, or incomplete exact-time range." /api/v1/auctions/{auctionId}: get: summary: Get public Auction detail operationId: getAuction tags: [Auctions] parameters: - name: auctionId in: path required: true schema: { type: string } description: Strict `auc_` UUIDv7 TypeID. responses: "200": description: "Public Auction facts, source summary, schedule, reported lot count, and visible listing count. Anonymous successful 200 responses without Authorization use `public, max-age=0, s-maxage=60, stale-if-error=0`; requests with any Authorization header and all non-200 responses use `private, no-store`." content: application/json: schema: $ref: "#/components/schemas/PublicAuctionData" "400": { description: Invalid Auction ID (`INVALID_OBJECT_ID`). } "404": { description: Auction missing (`AUCTION_NOT_FOUND`). } /api/v1/auctions/{auctionId}/product-listings: get: summary: Get public Auction catalogue operationId: getAuctionCatalogue tags: [Auctions] parameters: - name: auctionId in: path required: true schema: { type: string } - { name: language, in: query, schema: { type: string, default: en } } - { name: currency, in: query, schema: { type: string, default: EUR } } - { name: pageSize, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 21 }, } - name: searchAfter in: query description: Complete returned JSON cursor. It is scoped to this Auction and includes `auctionId`, catalogue position, and ProductListing ID. schema: { type: string } responses: "200": description: "Visible assigned ProductListings in normal personalized detail presentation, ordered by catalogue position, null positions last, then backing listing UUID. Anonymous successful 200 responses without Authorization use `public, max-age=0, s-maxage=60, stale-if-error=0`; requests with any Authorization header and all non-200 responses use `private, no-store`." content: application/json: schema: $ref: "#/components/schemas/PublicAuctionCatalogueData" "400": { description: Invalid Auction ID or cursor. } "404": { description: Auction missing (`AUCTION_NOT_FOUND`). } /api/v1/admin/auctions: get: summary: Search Auctions for administration operationId: adminSearchAuctions description: Administrator authority is required. Delegated Aura access tokens also require `auctions:read`; Cognito users do not require a delegated scope. Success and errors are always `no-store`. tags: [Auctions] security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: query in: query description: NUL-free, case-insensitive literal substring of the localized Auction name or sourceAuctionId. schema: { type: string } - { name: listingSourceId, in: query, schema: { type: string } } - name: sourceAuctionId in: query description: Exact source-scoped Auction key, trimmed as on create. Combine with listingSourceId to locate a create conflict. schema: { type: string } - { name: format, in: query, schema: { $ref: "#/components/schemas/AuctionFormatData" }, } - { name: reportedStatus, in: query, schema: { $ref: "#/components/schemas/AuctionReportedStatusData" }, } - name: sort in: query description: Supply both sort and order to override the default updated/descending ordering. schema: { type: string, enum: [name, created, updated], default: updated } - name: order in: query description: Supply both sort and order to override the default updated/descending ordering. schema: { type: string, enum: [asc, desc], default: desc } - name: size in: query description: Requested page limit, clamped to 1–100. schema: { type: integer, minimum: 1, maximum: 100, default: 21 } - name: searchAfter in: query description: Opaque cursor from the preceding page. Filters, sort and order must match the request that issued it. schema: { type: string } responses: "200": description: "All matching Auctions, regardless of status or visible listing count. Always `Cache-Control: no-store`." headers: Cache-Control: description: Always `no-store`. schema: { type: string, example: no-store } content: application/json: schema: { $ref: "#/components/schemas/AdminAuctionSearchCollectionData", } "400": description: Invalid filter, sort, or cursor (`BAD_QUERY_PARAMETER_VALUE`, `BAD_SORT_VALUE`, or `INVALID_OBJECT_ID`). "401": { description: Missing or invalid credentials (`INVALID_CREDENTIALS`)., } "403": description: Administrator authority and delegated `auctions:read` capability required (`FORBIDDEN`). "503": { description: Auction search temporarily unavailable (`AUCTION_TEMPORARILY_UNAVAILABLE`)., } post: summary: Create a source-scoped Auction (admin) description: Delegated Aura access tokens require `auctions:write`; missing scope returns `403 FORBIDDEN`. operationId: createAdminAuction tags: [Auctions] security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateAuctionData" responses: "201": description: Auction created. `Location` names the new admin detail resource. headers: Location: schema: { type: string } Cache-Control: description: Always `no-store`. schema: { type: string, example: no-store } content: application/json: schema: $ref: "#/components/schemas/AuctionAdminData" "400": { description: Invalid body or value (`BAD_BODY_VALUE`). } "401": { description: Missing or invalid credentials (`INVALID_CREDENTIALS`)., } "403": { description: Administrator authority required (`FORBIDDEN`). } "404": { description: ListingSource missing (`LISTING_SOURCE_NOT_FOUND`). } "409": { description: The ListingSource/sourceAuctionId key already exists (`CONFLICT`)., } "503": { description: Temporary Auction persistence failure (`AUCTION_TEMPORARILY_UNAVAILABLE`)., } /api/v1/admin/auctions/{auctionId}: get: summary: Get Auction administration detail operationId: getAdminAuction description: Administrator authority is required. Delegated Aura access tokens also require `auctions:read`; Cognito users do not require a delegated scope. Success and errors are always `no-store`. tags: [Auctions] security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: auctionId in: path required: true schema: { type: string } description: Strict `auc_` UUIDv7 TypeID. Bare UUIDs and wrong prefixes are invalid. responses: "200": description: "Current administrative Auction data. Always `Cache-Control: no-store`." headers: Cache-Control: description: Always `no-store`. schema: { type: string, example: no-store } content: application/json: schema: $ref: "#/components/schemas/AuctionAdminData" "400": { description: Invalid Auction ID (`INVALID_OBJECT_ID`). } "401": { description: Missing or invalid credentials (`INVALID_CREDENTIALS`)., } "403": description: Administrator authority and delegated `auctions:read` capability required (`FORBIDDEN`). "404": { description: Auction missing (`AUCTION_NOT_FOUND`). } "503": { description: Temporary Auction persistence failure (`AUCTION_TEMPORARILY_UNAVAILABLE`)., } patch: summary: Update Auction metadata (admin) description: Delegated Aura access tokens require `auctions:write`; missing scope returns `403 FORBIDDEN`. operationId: updateAdminAuction tags: [Auctions] security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: auctionId in: path required: true schema: { type: string } description: Strict `auc_` UUIDv7 TypeID. Auction identity and source key are immutable. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateAuctionData" responses: "200": description: "Updated administrative Auction data. Always `Cache-Control: no-store`." headers: Cache-Control: description: Always `no-store`. schema: { type: string, example: no-store } content: application/json: schema: $ref: "#/components/schemas/AuctionAdminData" "400": description: "Invalid body, expectedVersion, or schedule (`BAD_BODY_VALUE`)." "401": { description: Missing or invalid credentials (`INVALID_CREDENTIALS`)., } "403": { description: Administrator authority required (`FORBIDDEN`). } "404": { description: Auction missing (`AUCTION_NOT_FOUND`). } "409": { description: Stale expectedVersion (`CONFLICT`). } "503": { description: Temporary Auction persistence failure (`AUCTION_TEMPORARILY_UNAVAILABLE`)., } /api/v1/listing-sources/{listingSourceId}/ingestion-configurations/woocommerce: put: summary: Replace WooCommerce ListingSource ingestion configuration description: | Creates or completely replaces the WooCommerce ingestion configuration for a ListingSource. The caller must be a Cognito-authenticated user or Aura access token owner with Partnership write access to the source. Delegated Aura access tokens require `listing-sources:write`. This PUT atomically enables WOOCOMMERCE when needed. The webhook secret is required, nonblank, write-only, and never returned. Omitted or null currency and language clear those optional values. Repeating the same request is safe. operationId: putWoocommerceListingSourceIngestionConfiguration tags: - ListingSources parameters: - name: listingSourceId in: path required: true description: Strict `ls_` ListingSource TypeID. schema: { type: string, example: ls_6rd827eqfefsva9teecmwa3ate } security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PutWoocommerceListingSourceIngestionConfigurationData" example: webhookSecret: generated-provider-secret currency: EUR language: de responses: "201": description: WooCommerce was newly enabled and configured. No response body is returned. headers: Cache-Control: { description: Always `no-store`., schema: { type: string, example: no-store }, } "204": description: Existing WooCommerce configuration was replaced or already matched. No response body is returned. headers: Cache-Control: { description: Always `no-store`., schema: { type: string, example: no-store }, } "400": description: Invalid ListingSource ID (`INVALID_OBJECT_ID`), or malformed JSON, unknown request property, or invalid request value (`BAD_BODY_VALUE`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Missing or invalid bearer credential (`INVALID_CREDENTIALS`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Delegated scope missing or Partnership write access denied (`FORBIDDEN`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: Authorized ListingSource no longer exists (`LISTING_SOURCE_NOT_FOUND`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "409": description: Optimistic concurrency conflict (`CONFLICT`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "500": description: Unexpected internal failure (`LISTING_SOURCE_INTERNAL_ERROR`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Temporary authorization or persistence failure (`LISTING_SOURCE_TEMPORARILY_UNAVAILABLE`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" /api/v1/listing-sources/{listingSourceId}/ingestion-configurations/shopify: put: summary: Replace Shopify ListingSource ingestion configuration description: | Creates or completely replaces the Shopify ingestion configuration for a ListingSource. The caller must be a Cognito-authenticated user or Aura access token owner with Partnership write access to the source. Delegated Aura access tokens require `listing-sources:write`. This PUT atomically enables SHOPIFY when needed. The domain is validated and remains unique across configured sources. Omitted or null currency and language clear those optional values. Repeating the same request is safe. operationId: putShopifyListingSourceIngestionConfiguration tags: - ListingSources parameters: - name: listingSourceId in: path required: true description: Strict `ls_` ListingSource TypeID. schema: { type: string, example: ls_6rd827eqfefsva9teecmwa3ate } security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/PutShopifyListingSourceIngestionConfigurationData" example: domain: merchant.myshopify.com currency: EUR language: de responses: "201": description: Shopify was newly enabled and configured. No response body is returned. headers: Cache-Control: { description: Always `no-store`., schema: { type: string, example: no-store }, } "204": description: Existing Shopify configuration was replaced or already matched. No response body is returned. headers: Cache-Control: { description: Always `no-store`., schema: { type: string, example: no-store }, } "400": description: Invalid ListingSource ID (`INVALID_OBJECT_ID`), or malformed JSON, unknown request property, or invalid request value (`BAD_BODY_VALUE`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Missing or invalid bearer credential (`INVALID_CREDENTIALS`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Delegated scope missing or Partnership write access denied (`FORBIDDEN`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: Authorized ListingSource no longer exists (`LISTING_SOURCE_NOT_FOUND`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "409": description: Shopify domain uniqueness or optimistic concurrency conflict (`CONFLICT`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "500": description: Unexpected internal failure (`LISTING_SOURCE_INTERNAL_ERROR`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Temporary authorization or persistence failure (`LISTING_SOURCE_TEMPORARILY_UNAVAILABLE`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" /api/v1/listing-sources/{listingSourceId}/product-listings: post: summary: Batch create product-listings (Partner API) description: "Creates one or more product-listings for a listing source using bearer authentication. This endpoint is intended for partnerships and accepts: - a Cognito bearer token for the partner user linked to the listing source, or - an Aura Historia access token owned by that partner user. Aura Historia access tokens on this endpoint must include the `product-listings:write` scope. Allowed callers are Aura Historia admins and users partnered with the target listing source. The request body is an array of `CreateProductListingData` objects. Each entry is created synchronously in its own PostgreSQL transaction. Localized `title` and `description` are optional. Omit or send `null` when the source has no value to record. The response returns HTTP 200 with failures as `{ listingSourceId, sourceListingId, error }` objects when one or more entries succeed. `error` is the stable API error key for that entry. If every non-empty entry fails, the first failure is returned as a problem response. An empty array is accepted and returns `[]`. " operationId: postPartnerProductListings tags: - ProductListings parameters: - name: listingSourceId in: path required: true description: Unique identifier of the target ListingSource schema: type: string example: ls_6rd827eqfefsva9teecmwa3ate security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Array of at most 100 product-listings to create synchronously. May be empty. content: application/json: schema: type: array maxItems: 100 items: $ref: "#/components/schemas/CreateProductListingData" example: - sourceListingId: baroque-violin-001 title: text: Baroque Violin language: en description: text: A beautiful 18th-century baroque violin in excellent condition. language: en price: currency: EUR amount: 4500 availability: IN_STOCK url: https://my-listing-source.com/product-listings/baroque-violin images: - https://my-listing-source.com/images/violin-1.jpg - https://my-listing-source.com/images/violin-2.jpg responses: "200": description: "Batch create completed synchronously. This response is returned when all entries succeed or when at least one entry succeeds; it lists only failed entries. " headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/PartnerProductListingBatchFailuresResponse" examples: all_succeeded: summary: All product-listings were created value: [] partial_failure: summary: Some product-listings failed while at least one product was created value: - listingSourceId: ls_6rd827eqfefsva9teecmwa3ate sourceListingId: baroque-violin-002 error: CONFLICT "400": description: Bad request — request body is missing, empty, or contains invalid JSON content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Request body is absent or empty value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty. invalid_json: summary: Request body is not valid JSON value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: expected value at line 1 column 1 "401": description: "Unauthorized — the bearer token is missing, invalid, expired, or the referenced Aura Historia access token no longer exists. " content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_authorization: summary: Authorization header is missing value: status: 401 title: Unauthorized error: INVALID_CREDENTIALS source: field: Authorization type: HEADER access_token_not_found: summary: Aura Historia access token is unknown or expired value: status: 401 title: Unauthorized error: ACCESS_TOKEN_NOT_FOUND "403": description: Forbidden — the authenticated caller is not allowed to ingest product-listings for this listing source content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: Not found — the specified listing source does not exist content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: LISTING_SOURCE_NOT_FOUND "503": description: Service unavailable — all entries encountered a temporary product-write failure content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PRODUCT_LISTING_TEMPORARILY_UNAVAILABLE "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: PRODUCT_LISTING_INTERNAL_ERROR patch: summary: Batch update product-listings (Partner API) description: "Updates one or more existing product-listings for a listing source using bearer authentication. This endpoint is intended for partnerships and accepts: - a Cognito bearer token for the partner user linked to the listing source, or - an Aura Historia access token owned by that partner user. Aura Historia access tokens on this endpoint must include the `product-listings:write` scope. Allowed callers are Aura Historia admins and users partnered with the target listing source. The request body is an array of `UpdateProductListingData` objects. Omitted fields are unchanged; `null` clears availability and price. Omit `auction` to preserve its context; `auction: null`, `url: null`, and `images: null` return `400 BAD_BODY_VALUE`; send `[]` to remove all images. Within an asserted `auction`, omit a leaf to preserve it, send `null` to clear a clearable lot/timing leaf, or send a value to set it. `auction.auctionId` must name an existing Auction for this ListingSource. Omit it to preserve membership, send `null` to clear membership, or send an ID to set it. The complete batch contract is validated before any entry is applied synchronously in its own PostgreSQL transaction. The response returns HTTP 200 with failures as `{ listingSourceId, sourceListingId, error }` objects when one or more entries succeed. `error` is the stable API error key for that entry. If every non-empty entry fails, the first failure is returned as a problem response. An empty array is accepted and returns `[]`. " operationId: patchPartnerProductListings tags: - ProductListings parameters: - name: listingSourceId in: path required: true description: Unique identifier of the target ListingSource schema: type: string example: ls_6rd827eqfefsva9teecmwa3ate security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Array of at most 100 product updates to apply synchronously. May be empty. content: application/json: schema: type: array maxItems: 100 items: $ref: "#/components/schemas/UpdateProductListingData" example: - sourceListingId: baroque-violin-001 availability: null - sourceListingId: baroque-violin-002 price: currency: EUR amount: 5000 availability: IN_STOCK responses: "200": description: "Batch update completed synchronously. This response is returned when all entries succeed or when at least one entry succeeds; it lists only failed entries. " headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/PartnerProductListingBatchFailuresResponse" examples: all_succeeded: summary: All product-listings were updated value: [] partial_failure: summary: Some product-listings failed while at least one product was updated value: - listingSourceId: ls_6rd827eqfefsva9teecmwa3ate sourceListingId: baroque-violin-002 error: PRODUCT_LISTING_NOT_FOUND "400": description: Bad request — request body is missing, empty, or contains invalid JSON content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Request body is absent or empty value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty. invalid_json: summary: Request body is not valid JSON value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: expected value at line 1 column 1 "401": description: "Unauthorized — the bearer token is missing, invalid, expired, or the referenced Aura Historia access token no longer exists. " content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_authorization: summary: Authorization header is missing value: status: 401 title: Unauthorized error: INVALID_CREDENTIALS source: field: Authorization type: HEADER access_token_not_found: summary: Aura Historia access token is unknown or expired value: status: 401 title: Unauthorized error: ACCESS_TOKEN_NOT_FOUND "403": description: Forbidden — the authenticated caller is not allowed to ingest product-listings for this listing source content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: Not found — the specified listing source does not exist content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: LISTING_SOURCE_NOT_FOUND "503": description: Service unavailable — all entries encountered a temporary product-write failure content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PRODUCT_LISTING_TEMPORARILY_UNAVAILABLE "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: PRODUCT_LISTING_INTERNAL_ERROR put: summary: Batch upsert product-listings (Partner API) description: "Creates new product-listings or updates existing ones for a listing source in a single batch call,\nusing\ \ bearer authentication. This endpoint is intended for partnerships and accepts:\n- a Cognito bearer token for the\ \ partner user linked to the listing source, or\n- an Aura Historia access token owned by that partner user.\n\nAura\ \ Historia access tokens on this endpoint must include the `product-listings:write` scope.\nAllowed callers are Aura\ \ Historia admins and users partnered with the target listing source.\n\nThe request body is an array of `UpsertProductListingData`\ \ objects. Each entry is upserted\nsynchronously in its own PostgreSQL transaction. For each entry:\n- **New listing**\ \ — omitted or `null` availability, price, and estimates create no value; `auction` is omitted or an asserted nested Auction/lot-facts patch (not `null`).\n- **Existing listing** — availability, price, and each price estimate\n are tri-state: omitted preserves, `null` clears, and a concrete value replaces. Omit `auction` to preserve it; `auction: null` is invalid. Within an asserted Auction/lot-facts patch, each lot/timing leaf is tri-state: omit to preserve, `null` to clear clearable leaves, or provide a value to set. `auctionId` must name an existing Auction for this ListingSource; omit it to preserve membership, send `null` to clear it, or send an ID to set it. A withdrawn\n listing is restored before current facts\ \ apply.\n- `title` and `description` apply only on creation. For an\n existing\ \ listing they preserve current state and emit no current-state history event.\n- `images` is separate: omit to preserve,\ \ send `[]` to clear, or send an array to replace.\n `null` is invalid. `url` is non-clearable: omit or send `null`\ \ to preserve it; send a URL\n value to replace it.\n\nThe response returns HTTP 200 with failures as `{ listingSourceId,\ \ sourceListingId, error }` objects when\none or more entries succeed. `error` is the stable API error key for that\ \ entry. If every non-empty entry fails, the first failure is returned\nas a problem response. An empty array is accepted\ \ and returns `[]`.\n" operationId: putPartnerProductListings tags: - ProductListings parameters: - name: listingSourceId in: path required: true description: Unique identifier of the target ListingSource schema: type: string example: ls_6rd827eqfefsva9teecmwa3ate security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Array of at most 100 product-listings to upsert synchronously. May be empty. content: application/json: schema: type: array maxItems: 100 items: $ref: "#/components/schemas/UpsertProductListingData" examples: create_new: summary: Create a new product value: - sourceListingId: baroque-violin-001 title: text: Baroque Violin language: en description: text: A beautiful 18th-century baroque violin in excellent condition. language: en price: currency: EUR amount: 4500 availability: IN_STOCK url: https://my-listing-source.com/product-listings/baroque-violin images: - https://my-listing-source.com/images/violin-1.jpg update_existing: summary: Update an existing product while leaving the current price unchanged value: - sourceListingId: baroque-violin-001 availability: SOLD_OUT priceEstimateMin: currency: EUR amount: 4200 priceEstimateMax: currency: EUR amount: 4800 url: https://my-listing-source.com/product-listings/baroque-violin?status=sold images: - https://my-listing-source.com/images/violin-1.jpg - https://my-listing-source.com/images/violin-detail.jpg auction: lotNumber: "42A" cataloguePosition: 7 timing: biddingOpens: "2025-05-01T08:00:00Z" scheduledCloses: "2025-05-10T12:30:00Z" reportedClosedAt: "2025-05-10T12:45:00Z" clear_images: summary: Clear an existing product's images value: - sourceListingId: baroque-violin-001 images: [] responses: "200": description: "Batch upsert completed synchronously. This response is returned when all entries succeed or when at least one entry succeeds; it lists only failed entries. " headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/PartnerProductListingBatchFailuresResponse" examples: all_succeeded: summary: All product-listings were upserted value: [] partial_failure: summary: Some product-listings failed while at least one product was upserted value: - listingSourceId: ls_6rd827eqfefsva9teecmwa3ate sourceListingId: baroque-violin-002 error: BAD_BODY_VALUE "400": description: Bad request — request body is missing, empty, or contains invalid JSON content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Request body is absent or empty value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty. invalid_json: summary: Request body is not valid JSON value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: expected value at line 1 column 1 "401": description: "Unauthorized — the bearer token is missing, invalid, expired, or the referenced Aura Historia access token no longer exists. " content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_authorization: summary: Authorization header is missing value: status: 401 title: Unauthorized error: INVALID_CREDENTIALS source: field: Authorization type: HEADER access_token_not_found: summary: Aura Historia access token is unknown or expired value: status: 401 title: Unauthorized error: ACCESS_TOKEN_NOT_FOUND "403": description: Forbidden — the authenticated caller is not allowed to ingest product-listings for this listing source content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: Not found — the specified listing source does not exist content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: LISTING_SOURCE_NOT_FOUND "503": description: Service unavailable — all entries encountered a temporary product-write failure content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PRODUCT_LISTING_TEMPORARILY_UNAVAILABLE "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: PRODUCT_LISTING_INTERNAL_ERROR delete: summary: Batch delete product-listings (Partner API) description: "Soft-deletes product-listings for a listing source. Each entry writes its product lifecycle delete event and materialized PostgreSQL state synchronously in its own transaction. Allowed callers are Aura Historia admins and users partnered with the target listing source. Aura Historia access tokens must include the `product-listings:write` scope. The request body is an array of product identifiers. The response returns HTTP 200 with failures as `{ listingSourceId, sourceListingId, error }` objects when one or more entries succeed. `error` is the stable API error key for that entry. If every non-empty entry fails, the first failure is returned as a problem response. An empty array is accepted and returns `[]`. " operationId: deletePartnerProductListings tags: - ProductListings parameters: - name: listingSourceId in: path required: true description: Unique identifier of the target ListingSource schema: type: string example: ls_6rd827eqfefsva9teecmwa3ate security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Array of at most 100 product-listings to delete synchronously. May be empty. content: application/json: schema: type: array maxItems: 100 items: $ref: "#/components/schemas/WithdrawProductListingData" example: - sourceListingId: baroque-violin-001 responses: "200": description: "Batch delete completed synchronously. This response is returned when all entries succeed or when at least one entry succeeds; it lists only failed entries. " content: application/json: schema: $ref: "#/components/schemas/PartnerProductListingBatchFailuresResponse" examples: all_succeeded: value: [] partial_failure: value: - listingSourceId: ls_6rd827eqfefsva9teecmwa3ate sourceListingId: baroque-violin-002 error: PRODUCT_LISTING_NOT_FOUND "400": description: Bad request — request body is missing, empty, or contains invalid JSON content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Unauthorized — the bearer token is missing, invalid, expired, or unknown. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Forbidden — caller is neither admin nor partnered with this listing source, or the access token lacks `product-listings:write`. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: Not found — the specified listing source or product does not exist. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Service unavailable — all entries encountered a temporary product-write failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" /api/v1/listing-sources/{listingSourceId}/product-listings/async: post: summary: Submit a batch of product-listing creates asynchronously (Partner API) operationId: postAsyncPartnerProductListings tags: [ProductListings] description: | Submits the same JSON array of create objects as the synchronous POST, with up to 100 original entries. Accepts a partner user's Cognito access JWT or Aura access token; delegated access requires `product-listings:write`. No client-supplied queue or authority metadata is accepted. Each entry is parsed and validated independently after whole-request JSON/array/size validation; invalid entries do not prevent eligible siblings from being Existing create field rules apply (including optional `title` and `description`, omitted/null availability, optional pricing, and invalid outer `auction: null`). A syntactically valid missing Auction, existing listing key, partnership/source authority, lifecycle, and other business conflicts are decided downstream, not reported as immediate item failures. Only confirmed queue admission counts as accepted. `202` means admission, not creation, completion, rollback, or immediate search visibility. An unconfirmed send may already have been queued. `submissionId` is an opaque correlation identifier, not a job ID: there is no submission status endpoint, batch-level deduplication, or Location header. No created listing IDs or synchronous mutation results are returned. For a non-empty evaluated batch, at least one confirmed acceptance yields `202`, even with item failures. With zero accepted, any unconfirmed send or retryable send/deadline/FIFO blocked outcome yields `503`; otherwise internal/configuration failures yield `500`; otherwise all encoded-message-size failures yield `413`; remaining validation/value/size failures yield `400`. An empty array returns `202` after authentication and capability checks, with no sends. Every evaluated report uses the same JSON schema and echoes the effective `Idempotency-Key`, including non-2xx reports. Before item evaluation, bad path/key, malformed JSON, non-array, empty text, or over-100 array returns `400`; authentication `401`, insufficient capability `403`, whole-body/front-door limit `413`, and pre-evaluation internal/configuration or transient dependency failure `500` or `503`. These request-wide failures use `ApiError` and send nothing. Supply one `Idempotency-Key` for retries; a key is generated if omitted and echoed on evaluated responses. A lost response containing a generated key cannot be recovered. After transport uncertainty retry the exact unchanged ordered logical batch with the same key, including previously rejected entries at their original zero-based indices; never compact, reorder, or change its content under that key. Per-command downstream receipts deduplicate independently; the submission ID does not suppress the batch. Correct definitely invalid items in a separate request with a new key and do not include accepted/uncertain siblings. A same-group eligible successor is blocked when its FIFO predecessor is unresolved; unrelated groups may still be accepted. FIFO covers shared-queue acceptance per group, not cross-group or execution order. parameters: - name: listingSourceId in: path required: true description: Strict `ls_` ListingSource TypeID. schema: { type: string, example: ls_6rd827eqfefsva9teecmwa3ate } - $ref: "#/components/parameters/AsyncProductListingIdempotencyKey" security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Same array and item contract as synchronous create; individual invalid items produce report failures, not whole-batch rejection. content: application/json: schema: type: array maxItems: 100 items: $ref: "#/components/schemas/CreateProductListingData" example: - sourceListingId: SKU-001 title: { text: Baroque Violin, language: en } description: { text: An eighteenth-century violin., language: en } url: https://my-listing-source.com/product-listings/SKU-001 images: [https://my-listing-source.com/images/violin-1.jpg] responses: "202": description: At least one item confirmed admitted, or an authorized empty array. May include item-level failures. headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" examples: partial_admission: summary: Four original entries; indices 0 and 2 confirmed accepted value: submissionId: plis1_example acceptedCount: 2 failures: - { index: 1, sourceListingId: SKU-002, error: BAD_BODY_VALUE, retryable: false, } - { index: 3, sourceListingId: SKU-004, error: ENQUEUE_UNCONFIRMED, retryable: true, } empty_batch: summary: Empty authorized batch; no sends value: { submissionId: plis1_example, acceptedCount: 0, failures: [], } "400": description: Pre-evaluation invalid request (ApiError), or zero accepted with only item validation/value/size rejections (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: { status: 400, title: Bad Request, error: BAD_BODY_VALUE } application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" example: submissionId: plis1_example acceptedCount: 0 failures: - { index: 0, error: BAD_BODY_VALUE, retryable: false } "401": description: Missing or invalid bearer credential; no sends. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Insufficient credential capability; no sends. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "413": description: Whole-body/front-door limit before evaluation (ApiError), or zero accepted with only encoded-message-size item failures (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" example: submissionId: plis1_example acceptedCount: 0 failures: - { index: 0, sourceListingId: SKU-001, error: PRODUCT_LISTING_INGESTION_PAYLOAD_TOO_LARGE, retryable: false, } "500": description: Pre-evaluation internal/configuration failure (ApiError), or zero accepted with an item internal/configuration failure and no retryable send outcome (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" example: submissionId: plis1_example acceptedCount: 0 failures: - { index: 0, sourceListingId: SKU-001, error: PRODUCT_LISTING_INGESTION_INTERNAL_ERROR, retryable: false, } "503": description: Pre-evaluation transient dependency failure (ApiError), or zero accepted with an unconfirmed/retryable send, deadline or blocked outcome (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" example: submissionId: plis1_example acceptedCount: 0 failures: - { index: 0, sourceListingId: SKU-001, error: ENQUEUE_UNCONFIRMED, retryable: true, } - { index: 1, sourceListingId: SKU-001, error: ENQUEUE_BLOCKED, retryable: true, } patch: summary: Submit a batch of product-listing updates asynchronously (Partner API) operationId: patchAsyncPartnerProductListings tags: [ProductListings] description: | Submits the same JSON array of up to 100 `UpdateProductListingData` items as the synchronous PATCH. Accepts a partner user's Cognito access JWT or Aura access token; delegated access requires `product-listings:write`. No client-supplied queue or authority metadata is accepted. After whole-request JSON/array/size validation, each item is parsed and validated independently; invalid items do not prevent eligible siblings from being queued. The synchronous PATCH field rules apply: omit fields to preserve them; `null` clears availability, price, price estimates and clearable nested auction leaves; omit `auction` to preserve its context, or send an object to patch it. `auction: null`, `url: null` and `images: null` are invalid; `images: []` clears images. Omit `auction.auctionId` to preserve membership, use `null` to clear it or an ID to set it. A syntactically valid but missing listing or Auction, partnership/source authority, lifecycle and other business conflicts are checked downstream, not reported as immediate item failures or a synchronous `404`. Admission does not guarantee the patch is applied. Only confirmed queue admission counts as accepted. `202` means admission, not update completion, rollback, or immediate search visibility. An unconfirmed send may already have been queued. `submissionId` is an opaque correlation identifier, not a job ID: there is no submission status endpoint, batch-level deduplication, or Location header. No updated listing IDs or synchronous mutation results are returned. For a non-empty evaluated batch, at least one confirmed acceptance yields `202`, even with item failures. With zero accepted, any unconfirmed send or retryable send/deadline/FIFO blocked outcome yields `503`; otherwise internal/configuration failures yield `500`; otherwise all encoded-message-size failures yield `413`; remaining validation/value/size failures yield `400`. An empty array returns `202` after authentication and capability checks, with no sends. Every evaluated report uses the shared async batch JSON schema and echoes the effective `Idempotency-Key`, including non-2xx reports. Before item evaluation, bad path/key, malformed JSON, non-array, empty text, or over-100 array returns `400`; authentication `401`, insufficient capability `403`, whole-body/front-door limit `413`, and pre-evaluation internal/configuration or transient dependency failure `500` or `503`. These request-wide failures use `ApiError` and send nothing. Supply one `Idempotency-Key` for retries; a key is generated if omitted and echoed on evaluated responses. A lost response containing a generated key cannot be recovered. After transport uncertainty retry the exact unchanged ordered logical batch with the same key, including previously rejected entries at their original zero-based indices; never compact, reorder, or change its content under that key. Per-command downstream receipts deduplicate independently; the submission ID does not suppress the batch. Correct definitely invalid items in a separate request with a new key and do not include accepted/uncertain siblings. A same-group eligible successor is blocked when its FIFO predecessor is unresolved; unrelated groups may still be accepted. FIFO covers shared-queue acceptance per group, not cross-group or execution order. parameters: - name: listingSourceId in: path required: true description: Strict `ls_` ListingSource TypeID. schema: { type: string, example: ls_6rd827eqfefsva9teecmwa3ate } - $ref: "#/components/parameters/AsyncProductListingIdempotencyKey" security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Same array and item contract as synchronous PATCH; individual invalid items produce report failures, not whole-batch rejection. content: application/json: schema: type: array maxItems: 100 items: $ref: "#/components/schemas/UpdateProductListingData" example: - sourceListingId: baroque-violin-001 availability: null - sourceListingId: baroque-violin-002 url: null - sourceListingId: baroque-violin-003 price: { type: MONETARY, currency: EUR, amount: 5000 } - sourceListingId: baroque-violin-004 images: [] responses: "202": description: At least one update confirmed admitted, or an authorized empty array. May include item-level failures; no update completion implied. headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" examples: partial_admission: summary: Four original updates; indices 0 and 2 confirmed accepted value: submissionId: plis1_example acceptedCount: 2 failures: - { index: 1, sourceListingId: baroque-violin-002, error: BAD_BODY_VALUE, retryable: false, } - { index: 3, sourceListingId: baroque-violin-004, error: ENQUEUE_UNCONFIRMED, retryable: true, } empty_batch: summary: Empty authorized batch; no sends value: { submissionId: plis1_example, acceptedCount: 0, failures: [], } "400": description: Pre-evaluation invalid request (ApiError), or zero accepted with only item validation/value/size rejections (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" "401": description: Missing or invalid bearer credential; no sends. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Insufficient credential capability; no sends. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "413": description: Whole-body/front-door limit before evaluation (ApiError), or zero accepted with only encoded-message-size item failures (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" "500": description: Pre-evaluation internal/configuration failure (ApiError), or zero accepted with an item internal/configuration failure and no retryable send outcome (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" "503": description: Pre-evaluation transient dependency failure (ApiError), or zero accepted with an unconfirmed/retryable send, deadline or blocked outcome (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" put: summary: Submit a batch of product-listing upserts asynchronously (Partner API) operationId: putAsyncPartnerProductListings tags: [ProductListings] description: | Submits the same JSON array of up to 100 `UpsertProductListingData` items as the synchronous PUT. Accepts a partner user's Cognito access JWT or Aura access token; delegated access requires `product-listings:write`. No client-supplied queue or authority metadata is accepted. After whole-request JSON/array/size validation, items are parsed and validated independently; invalid items do not prevent eligible siblings from being queued. For a new listing, omitted or null availability, price and estimates create no value; `auction` may be omitted or asserted as an object, not null. For an existing listing, omitted availability, price, estimates and auction facts preserve their values; null clears clearable values and nested auction leaves. `auction.auctionId` may be omitted to preserve membership, null to clear it or an ID to set it. `images: []` clears images, while `images: null` and `auction: null` are invalid. An omitted or null `url` preserves an existing URL; a URL value replaces it. Title and description apply on creation only. Auction existence, listing state, partnership/source authority, lifecycle and other business conflicts are decided downstream, not as an immediate item failure or synchronous `404`. Only confirmed queue admission counts as accepted. `202` means admission, not an applied upsert, rollback, or immediate search visibility. An unconfirmed send may already have been queued. `submissionId` is an opaque correlation identifier, not a job ID; there is no submission status endpoint, batch-level deduplication, or Location header. No created or updated listing IDs or synchronous mutation results are returned. For a non-empty evaluated batch, at least one confirmed acceptance yields `202`, even with item failures. With zero accepted, an unconfirmed send or retryable send/deadline/FIFO blocked outcome yields `503`; otherwise internal/configuration failures yield `500`; otherwise all encoded-message-size failures yield `413`; remaining validation/value/size failures yield `400`. An empty array returns `202` after authentication and capability checks, with no sends. Every evaluated report uses the shared async batch JSON schema and echoes the effective `Idempotency-Key`, including non-2xx reports. Before evaluation, bad path/key, malformed JSON, non-array, empty text or over-100 array returns `400`; authentication `401`, insufficient capability `403`, whole-body/front-door limit `413`, and pre-evaluation internal/configuration or transient dependency failure `500` or `503`. These request-wide failures use `ApiError` and send nothing. Supply one `Idempotency-Key` for retries; a key is generated if omitted and echoed on evaluated responses. A lost response containing a generated key cannot be recovered. After transport uncertainty retry the exact unchanged ordered logical batch with the same key, including rejected items at their original zero-based indices; never compact, reorder or change its content under that key. Per-command downstream receipts deduplicate independently; the submission ID does not suppress the batch. Correct definitely invalid items separately with a new key, excluding accepted/uncertain siblings. A same-group eligible successor is blocked when its FIFO predecessor is unresolved; unrelated groups may still be accepted. FIFO covers shared-queue acceptance per group, not execution order. parameters: - name: listingSourceId in: path required: true description: Strict `ls_` ListingSource TypeID. schema: { type: string, example: ls_6rd827eqfefsva9teecmwa3ate } - $ref: "#/components/parameters/AsyncProductListingIdempotencyKey" security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Same array and item contract as synchronous PUT; individual invalid items produce report failures, not whole-batch rejection. content: application/json: schema: type: array maxItems: 100 items: $ref: "#/components/schemas/UpsertProductListingData" example: - sourceListingId: baroque-violin-001 title: { text: Baroque Violin, language: en } url: https://my-listing-source.com/product-listings/baroque-violin - sourceListingId: baroque-violin-002 images: [] - sourceListingId: baroque-violin-003 auction: null responses: "202": description: At least one upsert confirmed admitted, or an authorized empty array. May include item-level failures; no upsert completion implied. headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" examples: partial_admission: summary: Three original upserts; indices 0 and 1 confirmed accepted value: submissionId: plis1_example acceptedCount: 2 failures: - { index: 2, sourceListingId: baroque-violin-003, error: BAD_BODY_VALUE, retryable: false, } empty_batch: summary: Empty authorized batch; no sends value: { submissionId: plis1_example, acceptedCount: 0, failures: [], } "400": description: Pre-evaluation invalid request (ApiError), or zero accepted with only item validation/value/size rejections (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" "401": description: Missing or invalid bearer credential; no sends. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Insufficient credential capability; no sends. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "413": description: Whole-body/front-door limit before evaluation (ApiError), or zero accepted with only encoded-message-size item failures (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" "500": description: Pre-evaluation internal/configuration failure (ApiError), or zero accepted with an item internal/configuration failure and no retryable send outcome (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" "503": description: Pre-evaluation transient dependency failure (ApiError), or zero accepted with an unconfirmed/retryable send, deadline or blocked outcome (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" delete: summary: Submit a batch of product-listing withdrawals asynchronously (Partner API) operationId: deleteAsyncPartnerProductListings tags: [ProductListings] description: | Submits the same JSON array of up to 100 `WithdrawProductListingData` items as the synchronous DELETE, without changing that synchronous operation. Each item identifies a listing by `sourceListingId`; withdrawal is reversible, not physical deletion. Accepts a partner user's Cognito access JWT or Aura access token; delegated access requires `product-listings:write`. No client-supplied queue or authority metadata is accepted. After whole-request JSON/array/size validation, items are parsed and validated independently; invalid items do not prevent eligible siblings from being queued. Listing existence, partnership/source authority, lifecycle and other business conflicts are checked downstream, not as immediate item failures or a synchronous `404`. Only confirmed queue admission counts as accepted. `202` means admission, not an applied withdrawal, rollback, or immediate removal from public search. An unconfirmed send may already have been queued. `submissionId` is an opaque correlation identifier, not a job ID; there is no submission status endpoint, batch-level deduplication, or Location header. No synchronous deletion results or withdrawn listing IDs are returned. For a non-empty evaluated batch, at least one confirmed acceptance yields `202`, even with item failures. With zero accepted, an unconfirmed send or retryable send/deadline/FIFO blocked outcome yields `503`; otherwise internal/configuration failures yield `500`; otherwise all encoded-message-size failures yield `413`; remaining validation/value/size failures yield `400`. An empty array returns `202` after authentication and capability checks, with no sends. Every evaluated report uses the shared async batch JSON schema and echoes the effective `Idempotency-Key`, including non-2xx reports. Before evaluation, bad path/key, malformed JSON, non-array, empty text or over-100 array returns `400`; authentication `401`, insufficient capability `403`, whole-body/front-door limit `413`, and pre-evaluation internal/configuration or transient dependency failure `500` or `503`. These request-wide failures use `ApiError` and send nothing. Supply one `Idempotency-Key` for retries; a key is generated if omitted and echoed on evaluated responses. A lost response containing a generated key cannot be recovered. After transport uncertainty retry the exact unchanged ordered logical batch with the same key, including rejected items at their original zero-based indices; never compact, reorder or change its content under that key. Per-command downstream receipts deduplicate independently; the submission ID does not suppress the batch. Correct definitely invalid items separately with a new key, excluding accepted/uncertain siblings. A same-group eligible successor is blocked when its FIFO predecessor is unresolved; unrelated groups may still be accepted. FIFO covers shared-queue acceptance per group, not execution order. parameters: - name: listingSourceId in: path required: true description: Strict `ls_` ListingSource TypeID. schema: { type: string, example: ls_6rd827eqfefsva9teecmwa3ate } - $ref: "#/components/parameters/AsyncProductListingIdempotencyKey" security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Same array and item contract as synchronous DELETE; individual invalid items produce report failures, not whole-batch rejection. content: application/json: schema: type: array maxItems: 100 items: $ref: "#/components/schemas/WithdrawProductListingData" example: - sourceListingId: baroque-violin-001 - sourceListingId: " " - sourceListingId: baroque-violin-003 responses: "202": description: At least one withdrawal confirmed admitted, or an authorized empty array. May include item-level failures; no withdrawal completion implied. headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" examples: partial_admission: summary: Three original withdrawals; indices 0 and 2 confirmed accepted value: submissionId: plis1_example acceptedCount: 2 failures: - { index: 1, error: BAD_BODY_VALUE, retryable: false } empty_batch: summary: Empty authorized batch; no sends value: { submissionId: plis1_example, acceptedCount: 0, failures: [], } "400": description: Pre-evaluation invalid request (ApiError), or zero accepted with only item validation/value/size rejections (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" "401": description: Missing or invalid bearer credential; no sends. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Insufficient credential capability; no sends. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "413": description: Whole-body/front-door limit before evaluation (ApiError), or zero accepted with only encoded-message-size item failures (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" "500": description: Pre-evaluation internal/configuration failure (ApiError), or zero accepted with an item internal/configuration failure and no retryable send outcome (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" "503": description: Pre-evaluation transient dependency failure (ApiError), or zero accepted with an unconfirmed/retryable send, deadline or blocked outcome (batch report). headers: Idempotency-Key: $ref: "#/components/headers/AsyncProductListingIdempotencyKey" content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" application/json: schema: $ref: "#/components/schemas/AsyncProductListingBatchReport" /api/v1/webhooks/woocommerce/{listingSourceId}: post: summary: Ingest a WooCommerce product webhook (Partner API) description: "Accepts a single WooCommerce product webhook event for a partnership using bearer authentication. This endpoint is intended for partnerships and accepts: - a Cognito bearer token for the partner user linked to the listing source, or - an Aura Historia access token owned by that partner user. The caller must provide: - the bearer token in the `Authorization` header, - the WooCommerce topic in `x-wc-webhook-topic`, and - the base64-encoded HMAC-SHA256 signature over the exact, untouched request body bytes in `x-wc-webhook-signature`, and - optionally, the WooCommerce delivery identifier in `x-wc-webhook-delivery-id`. A supplied delivery identifier applies only when an event maps to raw capture. Its provider receipt retains only a canonical semantic source-payload SHA-256 evidence digest for 90 days. A captured-observation retry with the same digest may be deduplicated during downstream capture; reuse with different evidence fails in the consumer, not as an immediate HTTP `409`. Logical receipt expiry permits a new receipt but never removes or rewrites a captured raw revision or its provenance. A timestamp-free DELETE establishes a restore barrier. A later UPSERT without a provably newer `date_modified_gmt` fails during downstream capture (`WOOCOMMERCE_PROVIDER_SOURCE_ORDER_AMBIGUOUS`), not as an immediate HTTP `409`. Admission does not create a provider receipt or raw revision; investigate the failed FIFO command before reconciliation or redrive. The service verifies the signature over untouched body bytes before JSON parsing, then submits mapped observations as `CAPTURE_RAW` to the shared FIFO after bearer/capability checks and source configuration lookup. The consumer checks the current partner/source grant for mapped observations; ignored no-ops check it immediately. Only a matching, confirmed queue acceptance permits `204`; rejected, oversized, unconfirmed, and not-attempted submissions are not acknowledged. The FIFO consumer later commits raw capture with the command receipt; provider receipt and source-order decisions occur during that capture. Authorized ignored create/update events are no-op `204` without queue send or receipt, even when they include a delivery identifier. Retry an uncertain submission with the same signed body, topic, source, actor and delivery identifier where provided; without a delivery identifier, retries cannot recover the original command identity after a lost reply and have no provider receipt-based deduplication guarantee. A lost reply may already have enqueued work; never infer rollback from a non-204. Topic-specific payload requirements: - every topic requires `id` - `product.created` and `product.updated` with `status: publish` capture an UPSERT and require nonblank `name` and `permalink` - `product.created` and `product.updated` with `status: trash`, `draft`, `pending`, or `private` capture a DELETE and require only `id`; missing or unsupported statuses are authorized ignored events and also require only `id` - `product.deleted` captures a DELETE and requires only `id` The listing source identified by `listingSourceId` must have a WooCommerce ingestion configuration with a nonblank write-only `webhookSecret` and a configured language. A nonblank `price` maps to a `SET` and requires the listing source to have `woocommerceCurrency` configured. " operationId: postWoocommerceWebhook tags: - ProductListings security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: listingSourceId in: path required: true description: Unique identifier of the target ListingSource that should receive the WooCommerce webhook schema: type: string example: ls_6rd827eqfefsva9teecmwa3ate - name: x-wc-webhook-topic in: header required: true description: "WooCommerce webhook topic that determines how the payload is interpreted. Only the listed topic values are accepted. " schema: type: string enum: - product.created - product.updated - product.deleted example: product.created - name: x-wc-webhook-signature in: header required: true description: "Base64-encoded HMAC-SHA256 signature of the raw HTTP request body, calculated with the WooCommerce ingestion configuration's `webhookSecret`. " schema: type: string example: wqW/6B0S9myGxVQ8l3PPX2f6s4HWtY6q9KAr4m+Jv3E= - name: x-wc-webhook-delivery-id in: header required: false description: "Optional WooCommerce delivery identifier. For an event that maps to raw capture, its downstream provider receipt retains only a canonical semantic source-payload SHA-256 evidence digest for 90 days and deduplicates retries when applied. Reuse with different evidence fails during consumer capture, not as an immediate HTTP conflict. Logical receipt expiry permits a new receipt but never removes or rewrites a captured raw revision or its provenance. Authorized ignored create/update status events persist no receipt and receive no receipt-based retry-deduplication, even when this header is supplied. When absent, no provider receipt or receipt-based retry-deduplication guarantee is made." schema: type: string minLength: 1 maxLength: 512 example: 4d1f0a18-ec5e-4e97-8cf8-ff4edc8b2e31 requestBody: required: true description: "Topic-specific WooCommerce product payload. Every topic requires `id`. For `product.created` and `product.updated`, `status: publish` captures an UPSERT and requires nonblank `name` and `permalink`; `status: trash`, `draft`, `pending`, or `private` captures a DELETE and requires only `id`. Missing or unsupported create/update statuses are authorized ignored events and require only `id`. `product.deleted` captures a DELETE and requires only `id`; its other fields are optional and ignored when absent. WooCommerce `description` and `short_description` are accepted but ignored on all topics. They do not populate Aura's canonical product description and are omitted from persisted `source_payload`; provider-receipt evidence digests use this sanitized payload. The webhook signature is still verified over the exact original request body bytes. When present on an event that maps to raw capture, WooCommerce `date_modified_gmt` is the source ordering timestamp. It accepts a no-offset GMT value interpreted as UTC, RFC3339 `Z`, or RFC3339 `+00:00`; malformed or nonzero-offset values return `400 BAD_BODY_VALUE` before submission. Valid timestamps are checked for conflicts only during consumer capture. `product.created` and `product.updated` events with missing or unsupported status are ignored only after capability and source authorization, then acknowledge `204` without parsing `date_modified_gmt` or constructing a provider receipt; a denied ignored event returns `403 FORBIDDEN`. An authorized ignored event persists no provider receipt even if a delivery ID is supplied. Omit it when source order is unavailable; an omitted timestamp provides no source-ordering guarantee. " content: application/json: schema: anyOf: - $ref: "#/components/schemas/WoocommerceProductWebhookUpsertData" - $ref: "#/components/schemas/WoocommerceProductWebhookDeleteData" examples: created: summary: Product created webhook value: id: 17 name: Test Produkt Titel permalink: http://aura-historia-test.local/product/test-produkt-titel/ description: "
Hayde yallah test beschreibung
" short_description: "Hayde yallah kurze test beschreibung
" price: "42.69" status: publish stock_status: instock images: [] updated: summary: Product updated webhook value: id: 17 name: Test Produkt Titel permalink: http://aura-historia-test.local/product/test-produkt-titel/ description: "Hayde yallah test beschreibung
" short_description: "Hayde yallah kurze test beschreibung
" price: "123.45" status: publish stock_status: instock images: [] deleted: summary: Product deleted webhook value: id: 17 responses: "204": description: "Webhook bearer/capability, source configuration, and exact-body signature are validated. Current partner/source grant authorization for mapped commands happens at consumer execution; ignored no-ops check it before response. A `204` acknowledges either an authorized ignored create/update status (no queue send or receipt) or matching confirmed acceptance of one `CAPTURE_RAW` command by the shared ProductListing FIFO. It does not confirm raw capture, provider receipt persistence, source-order checks, canonical normalization, or search visibility. Those decisions occur when the consumer executes the command. Ignored events do not parse `date_modified_gmt` or construct a provider receipt. When a delivery ID or source timestamp is omitted, no corresponding receipt or source-ordering guarantee is made. The backend returns no response body on success. " headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" "400": description: "Bad request — invalid or missing listing source ID, missing body, malformed JSON, unsupported WooCommerce topic, an invalid `date_modified_gmt` source timestamp (including a nonzero offset) for an event that maps to raw capture, or a missing field required by the selected capture operation. " content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_listing_source_id: summary: Missing listing source ID path parameter value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: listingSourceId type: PATH detail: Missing field 'listingSourceId'. invalid_listing_source_id: summary: Invalid listing source ID format value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: listingSourceId type: PATH detail: must be a valid ListingSource ID missing_body: summary: Request body is absent or empty value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty. invalid_json: summary: Request body is not valid JSON value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: expected value at line 1 column 1 missing_topic: summary: WooCommerce topic header is missing value: status: 400 title: Bad Request error: BAD_HEADER_VALUE source: field: x-wc-webhook-topic type: HEADER "401": description: "Unauthorized — missing or invalid bearer credentials use `INVALID_CREDENTIALS`. A missing or invalid WooCommerce signature uses `BAD_HEADER_VALUE`. " content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_authorization: summary: Authorization header is missing value: status: 401 title: Unauthorized error: INVALID_CREDENTIALS source: field: Authorization type: HEADER invalid_access_token: summary: Aura Historia access token is unknown or expired value: status: 401 title: Unauthorized error: INVALID_CREDENTIALS missing_signature: summary: WooCommerce signature header is missing value: status: 401 title: Unauthorized error: BAD_HEADER_VALUE source: field: x-wc-webhook-signature type: HEADER detail: WooCommerce signature header is required. signature_mismatch: summary: WooCommerce signature does not match the request body value: status: 401 title: Unauthorized error: BAD_HEADER_VALUE source: field: x-wc-webhook-signature type: HEADER detail: WooCommerce signature is invalid. "403": description: Forbidden — the caller lacks the required ProductListing write capability or exact source partnership grant, including for ignored status events content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: Not found — the specified listing source does not exist content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: LISTING_SOURCE_NOT_FOUND "413": description: Payload too large — the HTTP body limit or encoded SQS message limit was exceeded before confirmed admission. No queue acceptance is claimed. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: body_limit: value: status: 413 title: Payload Too Large error: BAD_BODY_VALUE encoded_message_limit: value: status: 413 title: Payload Too Large error: PRODUCT_LISTING_INGESTION_PAYLOAD_TOO_LARGE "503": description: Service unavailable — authentication or source lookup is temporarily unavailable, or mapped command admission is rejected retryably, unconfirmed, or not attempted (including timeout). A send may already have succeeded when its acknowledgment was lost; retry unchanged. Uses `AUTH_TEMPORARILY_UNAVAILABLE`, `LISTING_SOURCE_TEMPORARILY_UNAVAILABLE`, or `PRODUCT_LISTING_TEMPORARILY_UNAVAILABLE`. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: auth_temporarily_unavailable: summary: Authentication is temporarily unavailable value: status: 503 title: Service Unavailable error: AUTH_TEMPORARILY_UNAVAILABLE listing_source_temporarily_unavailable: summary: ListingSource access is temporarily unavailable value: status: 503 title: Service Unavailable error: LISTING_SOURCE_TEMPORARILY_UNAVAILABLE product_listing_temporarily_unavailable: summary: ProductListing ingestion queue admission is unavailable or unconfirmed value: status: 503 title: Service Unavailable error: PRODUCT_LISTING_TEMPORARILY_UNAVAILABLE "500": description: Internal server error — authentication/source lookup or a non-retryable ingestion setup/encoding failure prevented confirmed admission. A failed response never proves an attempted send was not queued. Uses `AUTH_INTERNAL_ERROR`, `LISTING_SOURCE_INTERNAL_ERROR`, or `PRODUCT_LISTING_INTERNAL_ERROR`. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: auth_internal_error: summary: Authentication failed internally value: status: 500 title: Internal Server Error error: AUTH_INTERNAL_ERROR listing_source_internal_error: summary: ListingSource access failed internally value: status: 500 title: Internal Server Error error: LISTING_SOURCE_INTERNAL_ERROR product_listing_internal_error: summary: ProductListing ingestion admission failed internally value: status: 500 title: Internal Server Error error: PRODUCT_LISTING_INTERNAL_ERROR /api/v1/webhooks/loops: post: summary: Apply a signed Loops preference webhook description: >- Accepts one Loops webhook signed over the exact received body bytes. No Aura/Cognito bearer is required; `webhook-id`, `webhook-timestamp`, and `webhook-signature` must form a valid, recent Loops proof. The request body is limited to 64 KiB. The currently supported `webhookSchemaVersion` is `1.0.0`. Supported `eventName` values are `contact.unsubscribed`, `contact.deleted`, `email.unsubscribed`, `contact.mailingList.subscribed`, `contact.mailingList.unsubscribed`, `email.resubscribed`, `email.hardBounced`, and `email.spamReported`. A verified unknown event name is receipted as ignored; malformed events and unsupported payload schema versions return an error for provider retry. `204` means the receipt and any local preference effects committed, or the authenticated delivery was an identical duplicate or a safely ignored event. It does not mean a marketing message was sent or delivered. Conflicting delivery identity returns `409`; temporary database/provider-reader failure or the 10-second processing budget returns retryable `503`. All responses are `no-store`. operationId: postLoopsPreferenceWebhook tags: [Newsletter] security: [] parameters: - name: webhook-id in: header required: true description: Loops delivery identifier used for committed receipt deduplication. schema: { type: string, minLength: 1, maxLength: 256 } - name: webhook-timestamp in: header required: true description: Unix timestamp covered by the Loops signature; stale proofs are rejected. schema: { type: string, pattern: "^[0-9]{1,20}$" } - name: webhook-signature in: header required: true description: Loops HMAC-SHA256 signature over delivery ID, timestamp, and exact raw body bytes. schema: { type: string, maxLength: 8192 } requestBody: required: true description: Loops webhook payload. The service verifies the signature before parsing or mapping the selected event. content: application/json: schema: type: object required: [webhookSchemaVersion, eventName, eventTime] properties: webhookSchemaVersion: { type: string, example: "1.0.0" } eventName: type: string description: Supported event names are listed in the operation description; verified unknown names are ignored and receipted. eventTime: { type: integer, format: int64, description: Provider event time in Unix seconds., } contactIdentity: type: object description: Required for supported contact and email events; verified unknown event names may be safely ignored without it. required: [id, email] properties: id: { type: string } email: { type: string } mailingList: type: object description: Required for supported contact.mailingList events; only the configured marketing list affects consent. required: [id] properties: id: { type: string } additionalProperties: true example: webhookSchemaVersion: "1.0.0" eventName: email.unsubscribed eventTime: 1791373200 contactIdentity: id: contact_fixture email: person@example.test responses: "204": description: Authenticated event receipt and required local effects committed, or identical duplicate/safe ignore. No response body. headers: Cache-Control: schema: { type: string, example: "private, no-store" } "400": description: Malformed body/event, unsupported payload schema version, or invalid authenticated event time. Uses `LOOPS_WEBHOOK_INVALID_BODY`. content: application/problem+json: schema: { $ref: "#/components/schemas/ApiError" } example: { status: 400, title: Bad Request, error: LOOPS_WEBHOOK_INVALID_BODY, } "401": description: Missing, invalid, stale, or ambiguous Loops proof. The response does not distinguish authentication failures. Uses `LOOPS_WEBHOOK_UNAUTHORIZED`. content: application/problem+json: schema: { $ref: "#/components/schemas/ApiError" } example: { status: 401, title: Unauthorized, error: LOOPS_WEBHOOK_UNAUTHORIZED, } "409": description: A verified delivery identifier was previously committed with different body bytes. Uses `LOOPS_WEBHOOK_CONFLICT`. content: application/problem+json: schema: { $ref: "#/components/schemas/ApiError" } example: { status: 409, title: Conflict, error: LOOPS_WEBHOOK_CONFLICT } "413": description: Request body exceeds 64 KiB. Uses `LOOPS_WEBHOOK_PAYLOAD_TOO_LARGE`. content: application/problem+json: schema: { $ref: "#/components/schemas/ApiError" } example: { status: 413, title: Payload Too Large, error: LOOPS_WEBHOOK_PAYLOAD_TOO_LARGE, } "500": description: Redacted internal signing-secret or cryptographic configuration failure. Uses `LOOPS_WEBHOOK_INTERNAL_ERROR`. content: application/problem+json: schema: { $ref: "#/components/schemas/ApiError" } example: { status: 500, title: Internal Server Error, error: LOOPS_WEBHOOK_INTERNAL_ERROR, } "503": description: Temporary persistence/provider-reader failure or exceeded processing budget. Retry the delivery. Uses `LOOPS_WEBHOOK_TEMPORARILY_UNAVAILABLE`. content: application/problem+json: schema: { $ref: "#/components/schemas/ApiError" } example: { status: 503, title: Service Unavailable, error: LOOPS_WEBHOOK_TEMPORARILY_UNAVAILABLE, } /api/v1/product-listings/by-slug/{productListingTitleSlugId}: get: summary: Get a single product by title slug description: >- Retrieves an active ProductListing by its immutable Aura-owned `productListingTitleSlugId`, derived from its title. Withdrawn listings return `404 PRODUCT_LISTING_NOT_FOUND`; this endpoint never returns `410`. Anonymous successful 200 responses without Authorization use `public, max-age=0, s-maxage=120, stale-if-error=0`; any request with Authorization and all non-200 responses use `private, no-store`. operationId: getProductListingByTitleSlug tags: - ProductListings parameters: - name: productListingTitleSlugId in: path required: true description: Immutable Aura-owned public locator derived from the listing title schema: type: string minLength: 8 maxLength: 120 pattern: "^[a-z0-9]+(-[a-z0-9]+)*-[0-9a-f]{6}$" example: museum-cabinet-18-19-century-a1b2c3 - name: language in: query required: false schema: $ref: "#/components/schemas/LanguageData" - name: currency in: query required: false schema: $ref: "#/components/schemas/CurrencyData" security: - BearerAuth: [] - {} responses: "200": description: ProductListing found and returned successfully headers: Cache-Control: description: Anonymous edge freshness is 120 seconds; credential-bearing responses are private and not stored. schema: { type: string } example: public, max-age=0, s-maxage=120, stale-if-error=0 content: application/json: schema: $ref: "#/components/schemas/PersonalizedProductListingDetailsData" "400": description: Invalid path or query parameter content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: ProductListing not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Product detail temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" /api/v1/product-listings/{productListingId}: get: summary: Get a single product description: "Retrieves a single product by its `productListingId`. Withdrawn listings return `404 PRODUCT_LISTING_NOT_FOUND`; this endpoint never returns `410`. `pricing.source` preserves seller-supplied source amounts and currencies. `pricing.display` contains HalfUp-converted amounts in the requested currency, and `pricing.valuation` identifies the persisted snapshot used. A sold Product may have no main price; then display prices are omitted while its immutable `SALE` valuation remains present. Currency defaults to `EUR`. Anonymous responses use freshness caching only: no `ETag` or `Last-Modified` validator is emitted because current display pricing may change when the selected persisted FX snapshot changes. An anonymous successful 200 response without Authorization uses `public, max-age=0, s-maxage=120, stale-if-error=0`; any request with Authorization and all non-200 responses use `private, no-store`. Responses always contain `item`, the product data. A valid user or delegated-user bearer token adds optional top-level `userState`; credential-bearing responses are not cached. " operationId: getProductListing tags: - ProductListings parameters: - name: productListingId in: path required: true description: Unique identifier of the ProductListing schema: type: string example: pl_5xdb465tg1enarx2knf04mxbxj - name: language in: query required: false description: Requested current title and description language. Defaults to `en`; unavailable translations fall back to stored content. schema: $ref: "#/components/schemas/LanguageData" - name: currency in: query required: false description: Display currency. Defaults to `EUR`. schema: $ref: "#/components/schemas/CurrencyData" security: - BearerAuth: [] - {} responses: "200": description: ProductListing found and returned successfully content: application/json: schema: $ref: "#/components/schemas/PersonalizedProductListingDetailsData" headers: Cache-Control: description: Anonymous edge freshness is 120 seconds; credential-bearing responses are private and not stored. schema: { type: string } example: public, max-age=0, s-maxage=120, stale-if-error=0 Content-Language: description: The language of the returned content schema: $ref: "#/components/schemas/LanguageData" example: de Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" "400": description: Bad request - invalid parameters content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: ProductListing not found, including a withdrawn listing content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: PRODUCT_LISTING_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: PRODUCT_LISTING_INTERNAL_ERROR "503": description: Product detail or notification state is temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PRODUCT_LISTING_TEMPORARILY_UNAVAILABLE /api/v1/product-listings/{productListingId}/history: get: summary: Get ProductListing history description: "Retrieves immutable domain history for one ProductListing by `productListingId`. Each array item is one committed `PRODUCT_LISTING_DISCOVERED` or `PRODUCT_LISTING_CHANGED` event, ordered by occurrence time and event ID. A changed item contains a deterministic ordered `changes` array; it is never split into synthetic entries. Discovery exposes image count, never source image URLs. Price snapshots preserve stored source amounts and currencies. Sale observations retain their immutable source provenance. Without `currency`, the response is unchanged. With `currency`, each monetary discovery price/estimate and each previous/current price/estimate change value may include `display` with `currency`, `amount`, `fxRateId` and `capturedAt`. The snapshot is the latest persisted capture at or before this entry's `timestamp`, including an exact capture-time match. Both sides of a change use that entry's snapshot, even if the source currency changed. Conversion uses HalfUp rounding and the requested currency's minor-unit exponent (JPY and KRW: 0; all others: 2). Same-currency amounts retain the snapshot provenance. Missing snapshots or source/target quotes omit `display` for that value; the response still succeeds, and consumers fall back to the labelled source value. ON_REQUEST and null values receive no display projection. No later snapshot, current rates or provider calls are used. Source values, event order and the changes array remain intact. Currency query variants are included in the shared edge cache key. " operationId: getProductListingHistory tags: - ProductListings parameters: - name: productListingId in: path required: true description: Unique ProductListing identifier schema: type: string example: pl_5xdb465tg1enarx2knf04mxbxj - name: currency in: query required: false description: Optional display currency for historical monetary values; omitted means source values only. schema: $ref: "#/components/schemas/CurrencyData" responses: "200": description: Anonymous successful 200 responses without Authorization use `public, max-age=0, s-maxage=300, stale-if-error=0`; any request with Authorization and all errors use `private, no-store`. headers: Cache-Control: schema: type: string example: public, max-age=0, s-maxage=300, stale-if-error=0 content: application/json: schema: type: array items: $ref: "#/components/schemas/ProductListingHistoryEntryData" examples: product_history: summary: Example ProductListing history value: - eventType: PRODUCT_LISTING_DISCOVERED productListingId: pl_5xdb465tg1enarx2knf04mxbxj eventId: evt_7s35w34ftcew1r4cransc55rt4 payload: listingSourceId: ls_6ckwc632p2e2q86nv92g9eyw9q sourceListingId: source-6ba7b810 pricing: price: type: MONETARY currency: EUR amount: 3000 availability: AVAILABLE url: https://listing-source.example/product-listings/6ba7b810 imageCount: 3 auction: lotNumber: "42A" cataloguePosition: 7 biddingOpens: "2026-09-01T08:00:00Z" scheduledCloses: "2026-09-01T10:00:00Z" reportedClosedAt: "2026-09-01T10:15:00Z" timestamp: "2026-09-01T10:00:00Z" - eventType: PRODUCT_LISTING_CHANGED productListingId: pl_5xdb465tg1enarx2knf04mxbxj eventId: evt_2mdmwstjvvfn3rmbakmarshhqg payload: changes: - type: MAIN_PRICE_CHANGED previous: type: MONETARY currency: EUR amount: 3000 current: type: MONETARY currency: EUR amount: 2999 - type: AVAILABILITY_CHANGED previous: AVAILABLE current: SOLD_OUT timestamp: "2026-09-01T10:15:00Z" historical_display: summary: A price change requested in RON, using the snapshot at the event timestamp value: - eventType: PRODUCT_LISTING_CHANGED productListingId: pl_5xdb465tg1enarx2knf04mxbxj eventId: evt_2mdmwstjvvfn3rmbakmarshhqg payload: changes: - type: MAIN_PRICE_CHANGED previous: type: MONETARY currency: EUR amount: 3000 display: currency: RON amount: 15000 fxRateId: fx_0cwktgjtwnf4tb6hf2f8zm0x5k capturedAt: "2026-09-01T10:00:00Z" current: type: MONETARY currency: SEK amount: 29999 display: currency: RON amount: 15000 fxRateId: fx_0cwktgjtwnf4tb6hf2f8zm0x5k capturedAt: "2026-09-01T10:00:00Z" timestamp: "2026-09-01T10:15:00Z" "400": description: Bad request - Invalid parameters, including unsupported currency (BAD_QUERY_PARAMETER_VALUE) content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: Product not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: PRODUCT_LISTING_NOT_FOUND "503": description: ProductListing history is temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PRODUCT_LISTING_TEMPORARILY_UNAVAILABLE "500": description: ProductListing history contains invalid stored event/FX data or a price conversion overflowed content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: PRODUCT_LISTING_INTERNAL_ERROR /api/v1/product-listings/{productListingId}/similar: get: summary: Get similar product-listings description: "Retrieves product-listings similar to the specified product using KNN search over text embeddings. When the product embedding is ready, the endpoint returns matching product-listings. If it is absent, the endpoint returns `202 Accepted` with a polling location. Ready entries return `displayPrice` in the requested currency and `priceValuation` metadata. Active ProductListings use one persisted snapshot pinned for the request; sold ProductListings use immutable sale-time values. Every ready entry contains `item`; a valid user or delegated-user bearer token adds `userState`. Ready anonymous 200 responses without Authorization use `public, max-age=0, s-maxage=300, stale-if-error=0`; any request with Authorization uses `private, no-store`. The `202 EmbeddingPending` response and all errors are always `private, no-store`. " operationId: getSimilarProductListings tags: - ProductListings parameters: - name: productListingId in: path required: true description: Unique identifier of the product schema: type: string example: pl_5xdb465tg1enarx2knf04mxbxj - name: language in: query required: false description: Language used for localized KNN result titles. Defaults to `en`. schema: $ref: "#/components/schemas/LanguageData" - name: currency in: query required: false description: Display currency for KNN result prices. Defaults to `EUR`. schema: $ref: "#/components/schemas/CurrencyData" security: - BearerAuth: [] - {} responses: "200": description: Ready anonymous responses without Authorization are shared for 300 seconds; credential-bearing responses are private and not stored. headers: Cache-Control: schema: { type: string } example: public, max-age=0, s-maxage=300, stale-if-error=0 content: application/json: schema: type: array items: $ref: "#/components/schemas/PersonalizedProductListingSummaryData" "202": description: Product embedding is not available yet. Poll the Location URL for KNN results. This response is never cached and uses `private, no-store`. headers: Cache-Control: schema: { type: string } example: private, no-store Location: description: URL to poll for similar product-listings once the embedding is available schema: type: string format: uri example: /api/v1/product-listings/pl_5xdb465tg1enarx2knf04mxbxj/similar "400": description: Bad request - invalid parameters content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: Product not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: PRODUCT_LISTING_NOT_FOUND detail: ProductListing with ListingSourceId 'ls_6rd827eqfefsva9teecmwa3ate' and SourceListingId '6ba7b810' not found. "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/product-listings: get: summary: Simple product search via query parameters description: "Performs canonical ProductListing search with query parameters. Text queries combine BM25 and embedding KNN retrieval when embedding generation succeeds; otherwise the backend falls back to BM25. Explicit non-score sorts use BM25. Any request with an Authorization header is private and not stored, including valid credentials that add user state. Anonymous successful 200 responses use `public, max-age=0, s-maxage=60, stale-if-error=0`; errors use `private, no-store`. Geographic predicates are AND; values in each country or subdivision set are OR. Missing geography never matches. Radius is inclusive in its supplied unit to the same recorded point used by distance ordering. Numeric origins never resolve from addresses/preferences. Distance ordering conflicts with sort and uses lexical text matching. Geographic responses are private, no-store and use eventually consistent OpenSearch projections; location updates can briefly lag in items, ordering, total and continuation. `language` defaults to `en` and `currency` defaults to `EUR`." operationId: simpleSearchProductListings tags: - ProductListings parameters: - name: geography in: query style: deepObject explode: true description: Advertised item geography; source defaults do not confirm individual physical custody. schema: {$ref: '#/components/schemas/GeographicSearchData'} - name: language in: query required: false description: Language used for search matching and localized response fields; defaults to `en` schema: $ref: "#/components/schemas/LanguageData" example: de - name: currency in: query required: false description: Currency used to select the indexed price field; defaults to `EUR`; no request-time currency conversion occurs schema: $ref: "#/components/schemas/CurrencyData" example: EUR - name: productQuery in: query required: false description: Optional text queries for product-listings. Multiple entries are ORed together. style: form explode: true schema: type: array items: type: string minLength: 1 example: - test - example - name: enhancedSearchDescription in: query required: false description: Optional natural-language description used to refine matching. schema: type: string minLength: 1 maxLength: 1000 - name: excludeProductId in: query required: false description: Optional product IDs to exclude from results. style: form explode: true schema: type: array items: type: string uniqueItems: true example: - pl_5xdb465tg1enarx2knf04mxbxj - name: listingSourceId in: query required: false description: Optional ListingSource IDs to include. A result must belong to one of the supplied sources. style: form explode: true schema: type: array items: type: string uniqueItems: true - name: excludeListingSourceId in: query required: false description: Optional ListingSource IDs to exclude from results. style: form explode: true schema: type: array items: type: string uniqueItems: true - name: auctionId in: query required: false description: Exact resolved Auction membership IDs. Repeat up to 100 distinct strict `auc_` TypeIDs; supplied IDs OR together and intersect all other filters. Listings without resolved membership do not match. style: form explode: true schema: type: array maxItems: 100 items: type: string uniqueItems: true - name: price in: query required: false description: "Optional price range filter in minor currency units (e.g. cents for most supported currencies, whole yen for JPY). Use `price[min]` and/or `price[max]` to specify the range bounds. " style: deepObject explode: true schema: type: object properties: min: type: integer minimum: 0 description: Minimum price (inclusive) in minor currency units for the selected indexed currency example: 1000 max: type: integer minimum: 0 description: Maximum price (inclusive) in minor currency units for the selected indexed currency example: 50000 - name: availability in: query required: false description: Optional exact availability assertions. Values are ORed. style: form explode: true schema: type: array items: $ref: "#/components/schemas/ListingAvailabilityData" uniqueItems: true example: - IN_STOCK - LIMITED_AVAILABILITY - name: created in: query required: false description: "Optional filter by product creation date range (RFC3339 format). Use `created[min]` and/or `created[max]` to specify the datetime bounds. " style: deepObject explode: true schema: type: object properties: min: type: string format: date-time description: Minimum creation datetime (inclusive, RFC3339 format) example: "2024-01-01T00:00:00Z" max: type: string format: date-time description: Maximum creation datetime (inclusive, RFC3339 format) example: "2024-12-31T23:59:59Z" - name: updated in: query required: false description: "Optional filter by product last-updated date range (RFC3339 format). Use `updated[min]` and/or `updated[max]` to specify the datetime bounds. " style: deepObject explode: true schema: type: object properties: min: type: string format: date-time description: Minimum last-updated datetime (inclusive, RFC3339 format) example: "2024-01-01T00:00:00Z" max: type: string format: date-time description: Maximum last-updated datetime (inclusive, RFC3339 format) example: "2024-12-31T23:59:59Z" - name: lotBiddingOpens in: query required: false description: "Optional exact lot-bidding-open range (RFC3339 instants). Use `lotBiddingOpens[min]` and/or `lotBiddingOpens[max]` for `[min, max)` bounds. Date-only and absent lot times never match this filter. " style: deepObject explode: true schema: type: object properties: min: type: string format: date-time description: Inclusive minimum exact lot bidding-open instant (RFC3339) example: "2025-05-01T00:00:00Z" max: type: string format: date-time description: Exclusive maximum exact lot bidding-open instant (RFC3339) example: "2025-05-31T23:59:59Z" - name: lotScheduledCloses in: query required: false description: "Optional exact lot-scheduled-close range (RFC3339 instants). Use `lotScheduledCloses[min]` and/or `lotScheduledCloses[max]` for `[min, max)` bounds. Date-only and absent lot times never match this filter. " style: deepObject explode: true schema: type: object properties: min: type: string format: date-time description: Inclusive minimum exact lot scheduled-close instant (RFC3339) example: "2025-05-01T00:00:00Z" max: type: string format: date-time description: Exclusive maximum exact lot scheduled-close instant (RFC3339) example: "2025-05-31T23:59:59Z" - name: sort in: query required: false description: Field to sort results by schema: $ref: "#/components/schemas/SortProductListingFieldData" example: created - name: order in: query required: false description: Sort order (only valid when sort is specified) schema: type: string enum: - asc - desc example: desc - name: searchAfter in: query required: false description: "Opaque ProductListing cursor for pagination. Pass the complete JSON object returned as `searchAfter` in the previous response as one query value. It pins the FX snapshot for the full cursor chain. " schema: type: string example: '{"fxRateId":"fx_0cwktgjtwnf4tb6hf2f8zm0x5k","searchAfter":[2999,"pl_5xdb465tg1enarx2knf04mxbxj"]}' - name: size in: query required: false description: Number of product-listings to return per page schema: type: integer minimum: 1 maximum: 100 default: 21 example: 5 security: - BearerAuth: [] - {} responses: "200": description: Simple search results returned successfully headers: Cache-Control: description: Anonymous responses without Authorization are shared for 60 seconds; credential-bearing responses are private and not stored. schema: type: string example: public, max-age=0, s-maxage=60, stale-if-error=0 Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/ProductListingSearchResultData" "400": description: Bad request - invalid query parameters content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_query: summary: Invalid query parameter payload value: status: 400 title: Bad Request error: BAD_BODY_VALUE invalid_sort_field: summary: Invalid sort field value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: sort type: QUERY detail: "Expected any of: 'score', 'price', 'updated', 'created'. Got: 'invalid'" invalid_order: summary: Invalid sort order value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: order type: QUERY detail: "Expected any of: 'asc' or 'desc'. Got: 'invalid'" "503": description: Product search or required personalized state is temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PRODUCT_LISTING_TEMPORARILY_UNAVAILABLE "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/search-filters: get: summary: List user search filters description: "Delegated Aura access tokens require `search-filters:read`; missing scope returns `403 FORBIDDEN`. Retrieves all search filters for the authenticated user. Uses the service's fixed collection ordering. Requires a Cognito JWT or an Aura access token with `search-filters:read`. " operationId: getUserSearchFilters tags: - Search Filters security: - BearerAuth: [] - AccessTokenAuth: [] responses: "200": description: Search filters retrieved successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/UserSearchFilterCollectionData" example: items: - userId: usr_5pvhvpxyhve6ts31n9x8c2y513 userSearchFilterId: sf_4hyqf0gyxveazss7nby5hve5x2 name: My Tech Store Search notifications: true state: ACTIVE search: language: en currency: USD productQuery: - antique clock - vintage clock price: min: 1000 max: 5000 availability: - IN_STOCK listingSourceId: - ls_6rd827eqfefsva9teecmwa3ate created: "2024-01-01T10:00:00Z" updated: "2024-01-01T12:00:00Z" from: 0 size: 1 total: 1 "401": description: Unauthorized - missing or invalid Cognito JWT or Aura access token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - Aura access token lacks the required `search-filters:read` scope content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR post: summary: Create a new search filter description: "Creates a new search filter for the authenticated user. The search filter configuration is provided in the request body. Returns the created search filter with generated ID and metadata. Requires a Cognito JWT or an Aura access token with `search-filters:write`. The number of allowed search filters and the set of usable search filter fields depend on the user's tier: - `FREE`: Up to 1 search filter. Allowed fields are `productQuery`, `price`, `state`, `excludeProductId`, and `lifecycle`. Other fields are forbidden and return `SEARCH_FILTER_RESTRICTED_FEATURE`. - `PRO`: Up to 5 search filters. All filter fields are allowed. - `ULTIMATE`: Unlimited search filters. All filter fields are allowed. " operationId: createUserSearchFilter tags: - Search Filters security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Search filter configuration with name and filter criteria content: application/json: schema: $ref: "#/components/schemas/PostUserSearchFilterData" example: name: My Tech Store Search search: language: en currency: USD productQuery: - antique clock - vintage clock price: min: 1000 max: 5000 availability: - IN_STOCK created: min: "2024-01-01T00:00:00Z" max: "2024-12-31T23:59:59Z" listingSourceId: - ls_6rd827eqfefsva9teecmwa3ate responses: "201": description: Search filter created successfully headers: Location: description: URL of the created search filter schema: type: string format: uri example: https://api.aura-historia.com/api/v1/me/search-filters/sf_4hyqf0gyxveazss7nby5hve5x2 Content-Language: description: The language of the returned content schema: $ref: "#/components/schemas/LanguageData" example: en Last-Modified: description: When the search filter was created/updated schema: type: string format: http-date example: Wed, 01 Jan 2024 12:00:00 GMT Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/UserSearchFilterData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 userSearchFilterId: sf_4hyqf0gyxveazss7nby5hve5x2 name: My Tech Store Search notifications: true state: ACTIVE search: language: en currency: USD productQuery: - antique clock - vintage clock price: min: 1000 max: 5000 availability: - IN_STOCK listingSourceId: - ls_6rd827eqfefsva9teecmwa3ate created: "2024-01-01T12:00:00Z" updated: "2024-01-01T12:00:00Z" "400": description: Bad request - invalid request body content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Missing request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty invalid_json: summary: Invalid JSON format value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Invalid JSON format "401": description: Unauthorized - missing or invalid Cognito JWT or Aura access token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - Aura access token lacks the required `search-filters:write` scope content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: User not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "422": description: Unprocessable Entity - search filter quota exceeded or restricted feature used content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: quota_exceeded: summary: Search filter quota exceeded value: status: 422 title: Unprocessable Content error: SEARCH_FILTER_QUOTA_EXCEEDED detail: Exceeded the maximum amount of search filters. There are already 1/1 search filters occupied. restricted_feature: summary: Search filter contains a field not available for the user's tier value: status: 422 title: Unprocessable Content error: SEARCH_FILTER_RESTRICTED_FEATURE detail: Search filter contains forbidden search field 'listingSourceName' which requires a higher user tier. "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/search-filters/{userSearchFilterId}: get: summary: Get a specific search filter description: "Delegated Aura access tokens require `search-filters:read`; missing scope returns `403 FORBIDDEN`. Retrieves a specific search filter by its ID for the authenticated user. Returns the complete search filter configuration and metadata. Requires a Cognito JWT or an Aura access token with `search-filters:read`. " operationId: getUserSearchFilter tags: - Search Filters parameters: - name: userSearchFilterId in: path required: true description: Unique identifier of the search filter schema: type: string example: sf_4hyqf0gyxveazss7nby5hve5x2 security: - BearerAuth: [] - AccessTokenAuth: [] responses: "200": description: Search filter found and returned successfully headers: Content-Language: description: The language of the returned content schema: $ref: "#/components/schemas/LanguageData" example: en Last-Modified: description: When the search filter was last updated schema: type: string format: http-date example: Wed, 01 Jan 2024 12:00:00 GMT Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/UserSearchFilterData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 userSearchFilterId: sf_4hyqf0gyxveazss7nby5hve5x2 name: My Tech Store Search notifications: true state: ACTIVE search: language: en currency: USD productQuery: - antique clock - vintage clock price: min: 1000 max: 5000 availability: - IN_STOCK listingSourceId: - ls_6rd827eqfefsva9teecmwa3ate created: "2024-01-01T10:00:00Z" updated: "2024-01-01T12:00:00Z" "400": description: Bad request - invalid parameters content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_search_filter_id: summary: Missing search filter ID value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: userSearchFilterId type: PATH invalid_object_id: summary: Invalid search filter ID format value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userSearchFilterId type: PATH detail: must be a valid UserSearchFilter ID "401": description: Unauthorized - missing or invalid Cognito JWT or Aura access token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - Aura access token lacks the required `search-filters:read` scope content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: Search filter not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: SEARCH_FILTER_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR delete: summary: Delete a search filter description: "Deletes a specific search filter by its ID for the authenticated user. The search filter must exist and belong to the authenticated user. Requires a Cognito JWT or an Aura access token with `search-filters:write`. " operationId: deleteUserSearchFilter tags: - Search Filters parameters: - name: userSearchFilterId in: path required: true description: Unique identifier of the search filter to delete schema: type: string example: sf_4hyqf0gyxveazss7nby5hve5x2 security: - BearerAuth: [] - AccessTokenAuth: [] responses: "204": description: Search filter deleted successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" "400": description: Bad request - invalid parameters content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_search_filter_id: summary: Missing search filter ID value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: userSearchFilterId type: PATH invalid_object_id: summary: Invalid search filter ID format value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userSearchFilterId type: PATH detail: must be a valid UserSearchFilter ID "401": description: Unauthorized - missing or invalid Cognito JWT or Aura access token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - Aura access token lacks the required `search-filters:write` scope content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: Search filter not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: SEARCH_FILTER_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR patch: summary: Update a search filter description: "Updates a specific search filter by its ID for the authenticated user. Allows partial updates: omitted members remain unchanged, documented nullable criteria accept `null` to clear, and `null` for required scalars or collections returns `400 BAD_BODY_VALUE`. `{}` returns the existing search filter unchanged; an empty HTTP body is invalid. Requires a Cognito JWT or an Aura access token with `search-filters:write`. The set of usable search filter fields depends on the user's tier: - `FREE`: Allowed fields are `productQuery`, `price`, `state`, `excludeProductId`, and `lifecycle`. Other fields are forbidden and return `SEARCH_FILTER_RESTRICTED_FEATURE`. - `PRO`: All filter fields are allowed. - `ULTIMATE`: All filter fields are allowed. " operationId: updateUserSearchFilter tags: - Search Filters parameters: - name: userSearchFilterId in: path required: true description: Unique identifier of the search filter to update schema: type: string example: sf_4hyqf0gyxveazss7nby5hve5x2 security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: "Partial search filter update data. `{}` is a no-op; an empty HTTP body is invalid. " content: application/json: schema: $ref: "#/components/schemas/PatchUserSearchFilterData" examples: partial_update: summary: Update specific fields value: name: Updated Filter Name search: price: min: 2000 max: 8000 listingSourceId: - ls_6rd827eqfefsva9teecmwa3ate update_name_only: summary: Update only the name value: name: New Filter Name disable_notifications: summary: Disable notifications for this search filter value: notifications: false enable_notifications: summary: Enable notifications for this search filter value: notifications: true deactivate_filter: summary: Deactivate this search filter manually value: state: INACTIVE_BY_USER reactivate_filter: summary: Reactivate this search filter value: state: ACTIVE update_filter_only: summary: Update only the filter criteria value: search: language: de currency: EUR listingSourceId: - ls_6rd827eqfefsva9teecmwa3ate empty_update: summary: No changes (returns existing filter) value: {} responses: "200": description: Search filter updated successfully headers: Content-Language: description: The language of the returned content schema: $ref: "#/components/schemas/LanguageData" example: en Last-Modified: description: When the search filter was last updated schema: type: string format: http-date example: Wed, 01 Jan 2024 12:30:00 GMT Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/UserSearchFilterData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 userSearchFilterId: sf_4hyqf0gyxveazss7nby5hve5x2 name: Updated Filter Name notifications: true state: ACTIVE search: language: en currency: USD productQuery: - antique clock - vintage clock price: min: 2000 max: 8000 availability: - IN_STOCK listingSourceId: - ls_6rd827eqfefsva9teecmwa3ate created: "2024-01-01T10:00:00Z" updated: "2024-01-01T12:30:00Z" "400": description: Bad request - invalid parameters or body content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_search_filter_id: summary: Missing search filter ID value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: userSearchFilterId type: PATH invalid_object_id: summary: Invalid search filter ID format value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userSearchFilterId type: PATH detail: must be a valid UserSearchFilter ID invalid_json: summary: Invalid JSON format value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Invalid JSON format "401": description: Unauthorized - missing or invalid Cognito JWT or Aura access token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - Aura access token lacks the required `search-filters:write` scope content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: Search filter or user not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: search_filter_not_found: summary: Search filter not found value: status: 404 title: Not Found error: SEARCH_FILTER_NOT_FOUND user_not_found: summary: User not found value: status: 404 title: Not Found error: USER_NOT_FOUND "422": description: Unprocessable Entity - restricted feature used for the user's tier or quota exceeded during reactivation content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: restricted_feature: summary: Reactivation blocked by tier-restricted features value: status: 422 title: Unprocessable Content error: SEARCH_FILTER_RESTRICTED_FEATURE detail: Search filter contains forbidden search field 'listingSourceName' which requires a higher user tier. quota_exceeded: summary: Reactivation blocked by search-filter quota value: status: 422 title: Unprocessable Content error: SEARCH_FILTER_QUOTA_EXCEEDED detail: Exceeded the maximum amount of search filters. There are already 1/1 search filters occupied. "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/search-filters/{userSearchFilterId}/matches: get: summary: List persisted matches for a saved search filter description: >- Delegated Aura access tokens require `search-filters:read`; missing scope returns `403 FORBIDDEN`. Returns persisted product-listing matches associated with the authenticated user’s saved search filter. Results are read from stored match state and returned with cursor-based pagination in ascending persisted match-creation order. This endpoint does not execute a live search or preview the filter against current product listings. New matches are discovered only by scheduled matching of active enhanced filters, subject to product-search projection lag. Non-enhanced filters do not discover new matches; their historical matches remain available. Match discovery and notifications are not synchronous with listing changes or filter creation. Requires a Cognito JWT or an Aura access token with `search-filters:read`. operationId: listSearchFilterMatches tags: - Search Filters parameters: - name: userSearchFilterId in: path required: true description: Canonical Aura Historia UserSearchFilter ID. schema: type: string example: sf_4hyqf0gyxveazss7nby5hve5x2 - name: language in: query required: false description: Preferred language for localized product content. Defaults to `en`. schema: $ref: "#/components/schemas/LanguageData" example: de - name: currency in: query required: false description: Currency used for the returned product-listing representation. Defaults to `EUR`. schema: $ref: "#/components/schemas/CurrencyData" example: EUR - name: size in: query required: false description: >- Requested page size. The runtime defaults to 21 and clamps successfully parsed unsigned values to the inclusive range 1..100: `0` becomes 1 and values above 100 become 100. Negative, malformed, and non-integer values are rejected with `BAD_QUERY_PARAMETER_VALUE`. schema: type: integer format: int64 default: 21 example: 21 - name: searchAfter in: query required: false description: >- Cursor returned by the preceding page. It is a JSON string containing `[RFC3339 persisted match creation timestamp, canonical ProductListing ID]`; send the returned tuple as this query parameter to continue. The timestamp and ProductListing ID make the ascending cursor tie-safe. schema: type: string example: '["2026-08-05T12:30:00Z","pl_6zydvb8xqqfcntt760grgm41t4"]' security: - BearerAuth: [] - AccessTokenAuth: [] responses: "200": description: Persisted search-filter matches retrieved successfully headers: Cache-Control: description: Cache control directive — always set to `no-store` schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/SearchFilterMatchProductCollectionData" "400": description: Bad request - invalid path or query parameter content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_search_after: summary: Malformed searchAfter cursor value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: searchAfter type: QUERY detail: searchAfter must contain an RFC3339 timestamp and ProductListing ID. invalid_size: summary: Malformed page size value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: size type: QUERY invalid_search_after_product_listing_id: summary: Noncanonical ProductListing ID in searchAfter value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: searchAfter type: QUERY detail: must be a valid ProductListing ID invalid_search_filter_id: summary: Invalid search filter ID format value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userSearchFilterId type: PATH detail: must be a valid UserSearchFilter ID "401": description: Unauthorized - missing or invalid Cognito JWT or Aura access token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - Aura access token lacks the required `search-filters:read` scope content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: Search filter not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: SEARCH_FILTER_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: SEARCH_FILTER_INTERNAL_ERROR "503": description: Persisted-match details or pricing data are temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: SEARCH_FILTER_TEMPORARILY_UNAVAILABLE /api/v1/me/search-filters/{userSearchFilterId}/matches/{productListingId}: patch: summary: Update feedback for a search-filter match description: 'Updates the authenticated user''s feedback for a specific product match created by one of their saved search filters. The match is addressed by the search filter ID and canonical product ID. Requires a Cognito JWT or an Aura access token with `search-filters:write`. The request body itself is required and must be a JSON object, but the `feedback` field is optional: - `{"feedback": true}` marks the match as relevant. - `{"feedback": false}` marks the match as not relevant. - `{}` performs a no-op update and returns the existing stored match unchanged. ' operationId: updateSearchFilterMatchFeedback tags: - Search Filters parameters: - name: userSearchFilterId in: path required: true description: Unique identifier of the saved search filter that produced the match schema: type: string example: sf_4hyqf0gyxveazss7nby5hve5x2 - name: productListingId in: path required: true description: Canonical identifier of the matched product schema: type: string example: pl_6zydvb8xqqfcntt760grgm41t4 security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: "Feedback patch for an existing search-filter product match. An empty JSON object `{}` is valid. Omitting `feedback` inside the JSON object leaves the stored feedback unchanged. " content: application/json: schema: $ref: "#/components/schemas/PatchUserSearchFilterMatchData" examples: mark_match_as_relevant: summary: Mark the match as relevant value: feedback: true mark_match_as_not_relevant: summary: Mark the match as not relevant value: feedback: false no_op_patch: summary: No-op patch returning the existing match unchanged value: {} responses: "200": description: Search-filter product match updated successfully headers: Last-Modified: description: When the search-filter product match was last updated schema: type: string format: http-date example: Wed, 01 Jan 2024 12:30:00 GMT Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/SearchFilterProductMatchData" examples: feedback_set_to_true: summary: Match feedback stored as relevant value: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 userSearchFilterId: sf_4hyqf0gyxveazss7nby5hve5x2 productListingId: pl_6zydvb8xqqfcntt760grgm41t4 originEventId: evt_08nrsmex2je2dvsyh01v2kh78a feedback: true created: "2024-01-01T10:00:00Z" updated: "2024-01-01T12:30:00Z" no_op_patch: summary: Empty patch returns the existing feedback state value: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 userSearchFilterId: sf_4hyqf0gyxveazss7nby5hve5x2 productListingId: pl_6zydvb8xqqfcntt760grgm41t4 originEventId: evt_08nrsmex2je2dvsyh01v2kh78a feedback: true created: "2024-01-01T10:00:00Z" updated: "2024-01-01T10:00:00Z" "400": description: Bad request - invalid parameters or body content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_search_filter_id: summary: Missing search filter ID value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: userSearchFilterId type: PATH missing_product_id: summary: Missing product ID value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: productListingId type: PATH invalid_search_filter_id: summary: Invalid search filter ID format value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userSearchFilterId type: PATH detail: must be a valid UserSearchFilter ID invalid_product_id: summary: Invalid product ID format value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: productListingId type: PATH detail: must be a valid ProductListing ID missing_body: summary: Missing request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty invalid_body: summary: Invalid request body format value: status: 400 title: Bad Request error: BAD_BODY_VALUE "401": description: Unauthorized - missing or invalid Cognito JWT or Aura access token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - Aura access token lacks the required `search-filters:write` scope content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: Search-filter product match not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: SEARCH_FILTER_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/watchlist: get: summary: List user's watchlist product-listings description: "Retrieves all product-listings in the authenticated user's watchlist in watchlist creation order. Each result contains current product data and complete user-specific state. Accepts Cognito JWT authentication or an Aura Historia access token with `watchlist:read`. " operationId: getWatchlistProductListings tags: - Watchlist parameters: - name: language in: query required: false description: Preferred language for localized content. Defaults to `en` when omitted. schema: $ref: "#/components/schemas/LanguageData" example: de - name: currency in: query required: false description: Display currency. Defaults to `EUR`. schema: $ref: "#/components/schemas/CurrencyData" - name: size in: query required: false description: ProductListings per page. Defaults to 21; values are clamped to 1..100. schema: type: integer minimum: 1 maximum: 100 default: 21 - name: searchAfter in: query required: false description: "JSON array cursor returned by the preceding page: [RFC3339 timestamp, ProductListing ID]." schema: type: string example: '["2026-08-04T12:34:56Z", "pl_5xdb465tg1enarx2knf04mxbxj"]' security: - BearerAuth: [] responses: "200": description: Watchlist product-listings retrieved successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: type: object required: - items - size properties: items: type: array items: $ref: "#/components/schemas/PersonalizedProductListingDetailsData" size: type: integer minimum: 0 maximum: 100 description: Number of items returned in the current page. searchAfter: type: array items: type: string minItems: 2 maxItems: 2 nullable: true example: items: - item: productListingId: pl_5xdb465tg1enarx2knf04mxbxj productListingTitleSlugId: smartphone-case-a1b2c3 eventId: evt_69wh1chr82fen9vvyk6n3mh80m listingSourceId: ls_6rd827eqfefsva9teecmwa3ate sourceListingId: 6ba7b810 listingSourceName: Tech Store title: text: Smartphone Case language: en availability: IN_STOCK lifecycle: ACTIVE url: https://tech-store.com/smartphone-case viewUrl: https://tech-store.com/smartphone-case?utm_source=aura_historia&utm_medium=referral images: - url: https://tech-store.com/images/case-1.jpg contentPolicy: decision: ALLOWED created: "2024-01-01T10:00:00Z" updated: "2024-01-01T12:00:00Z" userState: watchlist: watching: true notifications: false contentVisibility: showUnassessedOrSensitiveContent: false notification: unseenNotificationIds: [] searchFilter: matched: false hidden: false size: 21 searchAfter: null "400": description: Bad request - invalid parameters content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE detail: Query parameters are invalid. "401": description: Unauthorized - invalid or missing JWT token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: UNAUTHORIZED "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR "503": description: Product details, persisted FX snapshots, or notification state are temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: WATCHLIST_TEMPORARILY_UNAVAILABLE post: summary: Add product to watchlist description: "Adds a product to the authenticated user's watchlist. The request body requires canonical `productListingId` and may set `notifications`; notifications default to `true`. Active-entry quota depends on the user's tier: Free users may have 20, Pro users 100, and Ultimate users have no active-entry limit. Adding beyond the active quota returns a 422 Unprocessable Entity error. Returns the created `WatchlistEntryData`. Requires a Cognito JWT or an Aura access token with `watchlist:write`. " operationId: addWatchlistProduct tags: - Watchlist security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Canonical product identifier and optional notification preference. content: application/json: schema: $ref: "#/components/schemas/PostWatchlistData" example: productListingId: pl_5xdb465tg1enarx2knf04mxbxj notifications: true responses: "201": description: Watchlist entry created successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/WatchlistEntryData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 productListingId: pl_5xdb465tg1enarx2knf04mxbxj notifications: true state: ACTIVE "400": description: Bad request - invalid request body content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Missing request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty invalid_json: summary: Invalid JSON format value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Invalid JSON format "401": description: Unauthorized - missing or invalid Cognito JWT or Aura access token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - Aura access token lacks the required `watchlist:write` scope content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: User or ProductListing not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: user_not_found: value: status: 404 title: Not Found error: USER_NOT_FOUND product_listing_not_found: value: status: 404 title: Not Found error: PRODUCT_LISTING_NOT_FOUND "409": description: Watchlist entry already exists, or the ProductListing is withdrawn and cannot be watched content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: already_exists: value: status: 409 title: Conflict error: CONFLICT detail: Watchlist entry already exists. product_listing_unavailable: value: status: 409 title: Conflict error: PRODUCT_LISTING_UNAVAILABLE detail: ProductListing is unavailable. "422": description: Unprocessable Entity - watchlist quota exceeded content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 422 title: Unprocessable Content error: WATCHLIST_QUOTA_EXCEEDED detail: Exceeded the maximum amount of watchlist entries. There are already 20/20 active watchlist entries occupied. "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/admin/listing-sources: post: summary: Create a ListingSource as admin description: | Delegated Aura access tokens require `listing-sources:write`; missing scope returns `403 FORBIDDEN`. Creates a ListingSource for an authenticated administrator. `operator` accepts either an existing Party reference (`EXISTING` with `partyId`) or a new Party with name and optional contact details (`NEW`). Ingestion configuration, provider uniqueness, presentation, and referral validation remain service-owned. A WooCommerce ingestion configuration carries its required `webhookSecret` as a write-only member; it is never returned or logged. operationId: adminCreateListingSource tags: - ListingSources security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: ListingSource creation payload. content: application/json: schema: $ref: "#/components/schemas/CreateListingSourceData" responses: "201": description: ListingSource created successfully. headers: Location: description: URL of the created admin ListingSource detail resource. schema: type: string format: uri example: /api/v1/admin/listing-sources/ls_6rd827eqfefsva9teecmwa3ate content: application/json: schema: $ref: "#/components/schemas/ListingSourceReferenceData" "400": description: Bad request - missing, malformed, or invalid ListingSource body. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Unauthorized - missing or invalid bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Forbidden - this endpoint requires the ADMIN role. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: Referenced operator Party was not found. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "409": description: ListingSource or provider configuration conflicts with current state. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "500": description: Internal ListingSource creation failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: ListingSource creation is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" get: summary: Search ListingSources as admin description: | Delegated Aura access tokens require `listing-sources:read`; missing scope returns `403 FORBIDDEN`. Searches ListingSource records for authenticated administrators. `query` performs a case-insensitive substring search across the ListingSource name and stable slug, and also the operator Party name and slug. `name` restricts the substring match to the ListingSource name. `listingSourceId` and `listingSourceSlugId` are exact identity filters. `operatorPartyId` and `ingestionMethod` are exact filters. Results use deterministic cursor pagination. The default sort is `name` ascending; override it by providing both `sort` and `order`. Valid sort fields are `name`, `slug`, `created`, and `updated`; ListingSource ID is always the final deterministic tie-breaker. Page sizes are clamped to 1–100, with a default of 21. The returned ListingSource ID `searchAfter` cursor is omitted on the terminal page and should be sent with the same filters and sort. Responses always use `Cache-Control: no-store`. The result contains only safe business-resource fields: ListingSource identity and name, operator Party reference, active ingestion methods, presentation URLs, and referral summary. Provider credentials, webhook secrets, and crawler-local configuration are never returned. operationId: adminSearchListingSources tags: - ListingSources security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: query in: query required: false description: Optional case-insensitive substring query across source and operator Party text. schema: type: string example: antiques - name: name in: query required: false description: Optional case-insensitive substring filter for the ListingSource name. schema: type: string example: antiques - name: listingSourceId in: query required: false description: Optional exact ListingSource ID filter. schema: type: string example: ls_6rd827eqfefsva9teecmwa3ate - name: listingSourceSlugId in: query required: false description: Optional exact immutable ListingSource slug filter. schema: type: string example: antiques-and-more-550e8400-e29b-41d4-a716-446655440000 - name: operatorPartyId in: query required: false description: Optional exact operator Party ID filter. schema: type: string example: pty_11bczr8va9ek4abckdkrqda538 - name: ingestionMethod in: query required: false description: Optional exact active ingestion-method filter. schema: $ref: "#/components/schemas/ListingIngestionMethodData" example: PARTNER_API - name: sort in: query required: false description: "Sort field. Valid values are `name`, `slug`, `created`, and `updated`. The default is `name` ascending." schema: $ref: "#/components/schemas/SortListingSourceFieldData" example: name - name: order in: query required: false description: "Sort direction for `sort`. Provide both `sort` and `order` to override the default." schema: type: string enum: - asc - desc example: asc - name: searchAfter in: query required: false description: Opaque ListingSource ID cursor returned by the previous page. It is omitted when no next page exists. schema: type: string example: ls_01jw7j4azge008000000000003 - name: size in: query required: false description: Number of ListingSource summaries requested per page. The server clamps values to the inclusive range 1–100. schema: type: integer minimum: 1 maximum: 100 default: 21 example: 21 responses: "200": description: ListingSource summaries returned successfully. headers: Cache-Control: description: Responses are never stored because this is an administrator read. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header. schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/ListingSourceSearchCollectionData" example: items: - listingSourceId: ls_6rd827eqfefsva9teecmwa3ate listingSourceSlugId: antiques-and-more-550e8400-e29b-41d4-a716-446655440000 name: Antiques and More operator: partyId: pty_11bczr8va9ek4abckdkrqda538 partySlugId: antiques-operator-550e8400-e29b-41d4-a716-446655440001 name: Antiques Operator ingestionMethods: - PARTNER_API presentation: url: https://antiques.example/ image: https://antiques.example/logo.png referralConfiguration: type: PARTNERIZE camref: campaign123 created: "2026-01-01T10:00:00Z" updated: "2026-01-02T10:00:00Z" size: 21 searchAfter: ls_6rd827eqfefsva9teecmwa3ate "400": description: Bad request - invalid ListingSource search parameters. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_sort: summary: Invalid sort field value: status: 400 title: Bad Request error: BAD_SORT_VALUE source: field: sort type: QUERY invalid_object_id: summary: Invalid ListingSource ID value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: listingSourceId type: QUERY detail: Query parameter 'listingSourceId' must be a valid ListingSource ID invalid_query: summary: Invalid ingestion method, page size, or cursor value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: searchAfter type: QUERY "401": description: Unauthorized - invalid or missing bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the ADMIN role. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "500": description: Internal authentication or ListingSource search failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: LISTING_SOURCE_INTERNAL_ERROR "503": description: Authentication, authorization, or ListingSource search data is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: LISTING_SOURCE_TEMPORARILY_UNAVAILABLE /api/v1/admin/parties: post: summary: Create a Party as admin description: | Delegated Aura access tokens require `parties:write`; missing scope returns `403 FORBIDDEN`. Creates a Party for an authenticated administrator. The request accepts only the Party name and optional phone/email contact information. Party names trim outer Unicode whitespace, reject blank values, and reject values over 255 UTF-8 bytes. The Party slug is generated once from the canonical name and stable Party ID; it remains immutable if the Party is renamed later. operationId: adminCreateParty tags: - Party security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Party creation payload. content: application/json: schema: $ref: "#/components/schemas/CreatePartyData" example: name: Antiques and More phone: "+49 30 123456" email: contact@example.com responses: "201": description: Party created successfully. headers: Location: description: URL of the created admin Party detail resource. schema: type: string format: uri example: /api/v1/admin/parties/pty_4k4snxc3pkecc9yw66heemzyp0 Cache-Control: description: Responses are never stored because contact data is returned. schema: type: string example: no-store content: application/json: schema: $ref: "#/components/schemas/PartyData" example: partyId: pty_4k4snxc3pkecc9yw66heemzyp0 partySlugId: antiques-and-more-550e8400-e29b-41d4-a716-446655440000 name: Antiques and More contact: phone: "+49 30 123456" email: contact@example.com created: "2026-01-01T10:00:00Z" updated: "2026-01-01T10:00:00Z" "400": description: Bad request - missing, empty, malformed, or invalid Party body. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_name: summary: Invalid Party name value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: name must be nonblank and at most 255 UTF-8 bytes. invalid_contact_email: summary: Invalid Party email value: status: 400 title: Bad Request error: BAD_BODY_VALUE "401": description: Unauthorized - missing or invalid bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the ADMIN role. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "409": description: Conflict - the generated Party slug conflicts with current state. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: CONFLICT detail: Party conflicts with current state. "503": description: Authentication, authorization, or Party persistence is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PARTY_TEMPORARILY_UNAVAILABLE "500": description: Internal authentication or Party persistence failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: PARTY_INTERNAL_ERROR get: summary: Search parties as admin description: | Delegated Aura access tokens require `parties:read`; missing scope returns `403 FORBIDDEN`. Searches Party records for authenticated administrators. `query` performs a case-insensitive substring search across Party name, phone, and email. `name`, `phone`, and `email` restrict the substring match to one contact/name field. `created` and `updated` accept inclusive RFC3339 ranges using `min` and `max` query members. Results use deterministic cursor pagination. The default sort is `name` ascending; override it by providing both `sort` and `order`. Valid sort fields are `name`, `email`, `phone`, `created`, and `updated`; Party ID is always the final deterministic tie-breaker. Page sizes are clamped to 1–100, with a default of 21. The returned ListingSource ID `searchAfter` cursor is omitted on the terminal page and should be sent with the same filters and sort. Responses always use `Cache-Control: no-store` because contact data is returned. operationId: adminSearchParties tags: - Party security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: query in: query required: false description: Optional case-insensitive substring query across Party name, phone, and email. schema: type: string example: antiques - name: name in: query required: false description: Optional case-insensitive substring filter for the Party name. schema: type: string example: antiques - name: phone in: query required: false description: Optional case-insensitive substring filter for the Party phone number. schema: type: string example: "+49 30" - name: email in: query required: false description: Optional case-insensitive substring filter for the Party email address. schema: type: string example: contact@example.com - name: "created[min]" in: query required: false description: Optional inclusive lower bound for the Party creation timestamp (RFC3339). schema: type: string format: date-time example: "2026-01-01T00:00:00Z" - name: "created[max]" in: query required: false description: Optional inclusive upper bound for the Party creation timestamp (RFC3339). schema: type: string format: date-time example: "2026-12-31T23:59:59Z" - name: "updated[min]" in: query required: false description: Optional inclusive lower bound for the Party update timestamp (RFC3339). schema: type: string format: date-time example: "2026-01-01T00:00:00Z" - name: "updated[max]" in: query required: false description: Optional inclusive upper bound for the Party update timestamp (RFC3339). schema: type: string format: date-time example: "2026-12-31T23:59:59Z" - name: sort in: query required: false description: "Sort field. Valid values are `name`, `email`, `phone`, `created`, and `updated`. The default is `name` ascending." schema: $ref: "#/components/schemas/SortPartyFieldData" example: name - name: order in: query required: false description: "Sort direction for `sort`. Provide both `sort` and `order` to override the default." schema: type: string enum: - asc - desc example: asc - name: searchAfter in: query required: false description: Opaque Party ID cursor returned by the previous page. It is omitted when no next page exists. schema: type: string example: pty_01jw7j4azge008000000000002 - name: size in: query required: false description: Number of Party summaries requested per page. The server clamps values to the inclusive range 1–100. schema: type: integer minimum: 1 maximum: 100 default: 21 example: 21 responses: "200": description: Party summaries returned successfully. headers: Cache-Control: description: Responses are never stored because this administrator read contains contact data. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/PartyCollectionData" example: items: - partyId: pty_4k4snxc3pkecc9yw66heemzyp0 partySlugId: antiques-and-more-550e8400-e29b-41d4-a716-446655440000 name: Antiques and More contact: phone: "+49 30 123456" email: contact@example.com created: "2026-01-01T10:00:00Z" updated: "2026-01-02T10:00:00Z" size: 21 searchAfter: pty_4k4snxc3pkecc9yw66heemzyp0 "400": description: Bad request - invalid query parameters. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_sort_field: summary: Invalid sort field value: status: 400 title: Bad Request error: BAD_SORT_VALUE source: field: sort type: QUERY invalid_order: summary: Invalid sort order value: status: 400 title: Bad Request error: BAD_ORDER_VALUE source: field: order type: QUERY invalid_search_after: summary: Invalid searchAfter cursor value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: searchAfter type: QUERY detail: "searchAfter must contain a valid Party ID." invalid_size: summary: Invalid page size value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: size type: QUERY "401": description: Unauthorized - invalid or missing bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the ADMIN role. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "503": description: Authentication, authorization, or Party search data is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PARTY_TEMPORARILY_UNAVAILABLE "500": description: Internal authentication or Party search failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: PARTY_INTERNAL_ERROR /api/v1/admin/parties/{partyId}: delete: summary: Hard-delete an unused Party as admin description: | Delegated Aura access tokens require `parties:write`; missing scope returns `403 FORBIDDEN`. Deletes only an unused Party after commit. A Party with any ListingSource or retained Partnership, including `DISSOLVED`, returns `409 CONFLICT`; no dependent business or historical row is cascaded, detached, rewritten, or archived. Responses use `Cache-Control: no-store` and this operation accepts no request body. operationId: adminDeleteParty tags: - Party security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: partyId in: path required: true description: Stable Party identifier. schema: type: string example: pty_4k4snxc3pkecc9yw66heemzyp0 responses: "204": description: Party deleted successfully. headers: Cache-Control: description: Response is never stored. schema: type: string example: no-store "400": description: Invalid Party ID. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Missing or invalid bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Administrator authority is required. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: Party was not found, including after a successful prior delete. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "409": description: Party has a ListingSource or retained Partnership, or changed concurrently. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Party persistence is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "500": description: Party persistence failed internally. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" patch: summary: Update a Party as admin description: | Delegated Aura access tokens require `parties:write`; missing scope returns `403 FORBIDDEN`. Updates the name and/or contact information for a Party for an authenticated administrator. Only `name`, `phone`, and `email` are supported. Omitted members remain unchanged; `null` clears `phone` or `email`; `name` is not nullable and `name: null` is rejected. Party names trim outer Unicode whitespace, reject blank values, and reject values over 255 UTF-8 bytes. Renaming a Party never changes its immutable slug. The response is the resulting Party representation and uses `Cache-Control: no-store` because contact data is returned. An empty object is a valid no-op PATCH; an empty HTTP body is invalid. operationId: adminUpdateParty tags: - Party security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: partyId in: path required: true description: Stable Party identifier. schema: type: string example: pty_4k4snxc3pkecc9yw66heemzyp0 requestBody: required: true description: Party name/contact patch. Omit unchanged members; null clears phone/email only. content: application/json: schema: $ref: "#/components/schemas/UpdatePartyData" examples: rename: summary: Rename without changing the Party slug value: name: Antiques and More set_contact: summary: Set optional contact values value: phone: "+49 30 123456" email: contact@example.com clear_contact: summary: Clear optional contact values value: phone: null email: null no_op_patch: summary: Leave the Party unchanged value: {} responses: "200": description: Party updated successfully. headers: Cache-Control: description: Responses are never stored because contact data is returned. schema: type: string example: no-store content: application/json: schema: $ref: "#/components/schemas/PartyData" example: partyId: pty_4k4snxc3pkecc9yw66heemzyp0 partySlugId: antiques-and-more-550e8400-e29b-41d4-a716-446655440000 name: Antiques and More contact: phone: "+49 30 123456" email: contact@example.com created: "2026-01-01T10:00:00Z" updated: "2026-01-02T10:00:00Z" "400": description: Bad request - invalid Party ID, empty/malformed body, or invalid Party value. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_party_id: summary: Invalid Party ID value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: partyId type: PATH detail: must be a valid Party ID invalid_name: summary: Invalid Party name value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: name must be nonblank and at most 255 UTF-8 bytes. invalid_email: summary: Invalid Party email value: status: 400 title: Bad Request error: BAD_BODY_VALUE nullable_name: summary: Required Party name cannot be cleared value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body field 'name' must not be null. "401": description: Unauthorized - missing or invalid bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the ADMIN role. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "404": description: Party was not found. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: PARTY_NOT_FOUND detail: Party was not found. "409": description: Conflict - the Party was changed concurrently. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: CONFLICT detail: Party conflicts with current state. "503": description: Authentication, authorization, or Party persistence is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PARTY_TEMPORARILY_UNAVAILABLE "500": description: Internal authentication or Party persistence failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: PARTY_INTERNAL_ERROR get: summary: Get a Party as admin description: | Delegated Aura access tokens require `parties:read`; missing scope returns `403 FORBIDDEN`. Gets one Party for an authenticated administrator. `partyId` must be a valid Party ID. The response contains the Party identity, immutable slug, name, optional phone/email contact information, and creation/update timestamps. Responses always use `Cache-Control: no-store` because contact data is returned. operationId: adminGetParty tags: - Party security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: partyId in: path required: true description: Stable Party identifier. schema: type: string example: pty_4k4snxc3pkecc9yw66heemzyp0 responses: "200": description: Party returned successfully. headers: Cache-Control: description: Responses are never stored because contact data is returned. schema: type: string example: no-store content: application/json: schema: $ref: "#/components/schemas/PartyData" example: partyId: pty_4k4snxc3pkecc9yw66heemzyp0 partySlugId: antiques-and-more-550e8400-e29b-41d4-a716-446655440000 name: Antiques and More contact: phone: "+49 30 123456" email: contact@example.com created: "2026-01-01T10:00:00Z" updated: "2026-01-02T10:00:00Z" "400": description: Bad request - invalid Party ID. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: partyId type: PATH detail: must be a valid Party ID "401": description: Unauthorized - missing or invalid bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the ADMIN role. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "404": description: Party was not found. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: PARTY_NOT_FOUND detail: Party was not found. "503": description: Authentication or Party persistence is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: PARTY_TEMPORARILY_UNAVAILABLE "500": description: Internal authentication or Party persistence failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: PARTY_INTERNAL_ERROR /api/v1/admin/users: get: summary: Search users as admin description: "Searches users across all accounts for authenticated administrators. Text filters use case-insensitive substring matching. `query` searches email, first name, and last name; `email`, `firstName`, and `lastName` restrict the match to one field. `tier` and `role` filters use exact values. Results use deterministic keyset pagination. The default sort is `name` ascending; override it by providing both `sort` and `order`. Every sort uses `userId` as a deterministic tie-breaker. This response always uses `Cache-Control: no-store`. " operationId: adminSearchUsers tags: - User Account security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: query in: query required: false description: Optional case-insensitive substring query across email, first name, and last name. schema: type: string example: ada - name: email in: query required: false description: Optional case-insensitive substring filter for the email address. schema: type: string example: ada@example.com - name: firstName in: query required: false description: Optional case-insensitive substring filter for the first name. schema: type: string example: Ada - name: lastName in: query required: false description: Optional case-insensitive substring filter for the last name. schema: type: string example: Lovelace - name: tier in: query required: false description: Optional filter by one or more user subscription tiers. style: form explode: true schema: type: array items: $ref: "#/components/schemas/UserTierData" uniqueItems: true example: - PRO - ULTIMATE - name: role in: query required: false description: Optional filter by one or more user roles. style: form explode: true schema: type: array items: $ref: "#/components/schemas/UserRoleData" uniqueItems: true example: - ADMIN - name: created[min] in: query required: false description: Optional lower bound for the user's `created` timestamp (RFC3339). schema: type: string format: date-time example: "2026-01-01T00:00:00Z" - name: created[max] in: query required: false description: Optional upper bound for the user's `created` timestamp (RFC3339). schema: type: string format: date-time example: "2026-12-31T23:59:59Z" - name: updated[min] in: query required: false description: Optional lower bound for the user's `updated` timestamp (RFC3339). schema: type: string format: date-time example: "2026-04-01T00:00:00Z" - name: updated[max] in: query required: false description: Optional upper bound for the user's `updated` timestamp (RFC3339). schema: type: string format: date-time example: "2026-04-25T23:59:59Z" - name: sort in: query required: false description: "Field used for ordering results. Valid fields are `name`, `email`, `firstName`, `lastName`, `tier`, `role`, `created`, and `updated`. The default is `name` ascending. To override it, provide both `sort` and `order`. " schema: $ref: "#/components/schemas/SortUserFieldData" example: email - name: order in: query required: false description: "Sort direction for `sort`. Ignored unless `sort` is also provided; when both are absent, results use `name` ascending. " schema: type: string enum: - asc - desc example: asc - name: searchAfter in: query required: false description: "Opaque User ID cursor for keyset pagination. Pass the `searchAfter` string returned by the previous response to fetch the next page. Requests may also provide the legacy JSON array form when its final element is a valid User ID. The cursor is valid only with the same filters and sort used for the previous page. " schema: type: string example: usr_01jw7j4azge008000000000004 - name: size in: query required: false description: Number of users requested per page. The server clamps values to the inclusive range 1–100. schema: type: integer minimum: 1 maximum: 100 default: 21 example: 21 responses: "200": description: Users returned successfully. headers: Cache-Control: description: Responses are never stored because this is an administrator-only user read. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/UserCollectionData" example: items: - userId: usr_5pvhvpxyhve6ts31n9x8c2y513 email: ada.admin@example.com firstName: Ada lastName: Lovelace tier: ULTIMATE role: ADMIN stripeCustomerId: cus_admin_550e8400e29b41d4a716446655440000 - userId: usr_681w9znhe8eawrhebxd1046d44 email: grace.user@example.com firstName: Grace lastName: Hopper tier: PRO role: USER size: 2 searchAfter: usr_681w9znhe8eawrhebxd1046d44 "400": description: Bad request - invalid query parameters. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_query: summary: Invalid query parameter value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE invalid_sort_field: summary: Invalid sort field value: status: 400 title: Bad Request error: BAD_SORT_VALUE source: field: sort type: QUERY detail: "Expected any of: 'name', 'email', 'firstName', 'lastName', 'tier', 'role', 'updated', 'created'. Got: 'invalid'" invalid_order: summary: Invalid sort order value: status: 400 title: Bad Request error: BAD_ORDER_VALUE source: field: order type: QUERY detail: "Expected any of: 'asc', 'desc'. Got: 'invalid'" invalid_search_after: summary: Invalid searchAfter cursor value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: searchAfter type: QUERY detail: "searchAfter must contain a valid User ID." invalid_size: summary: Invalid page size value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: size type: QUERY detail: invalid digit found in string "401": description: Unauthorized - invalid or missing bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the `ADMIN` role and `users:read` capability when delegated. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "503": description: Authentication, authorization, or user search data is temporarily unavailable (`AUTH_TEMPORARILY_UNAVAILABLE` or `USER_TEMPORARILY_UNAVAILABLE`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: USER_TEMPORARILY_UNAVAILABLE "500": description: Internal authentication or user search failure (`AUTH_INTERNAL_ERROR` or `USER_INTERNAL_ERROR`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: USER_INTERNAL_ERROR /api/v1/admin/users/{userId}: get: summary: Get a user as admin description: "Retrieves a single user account by user ID for authenticated administrators. Cognito JWTs and Aura Historia access tokens are accepted; delegated access tokens require `users:read`. The response always sends `Cache-Control: no-store`. " operationId: adminGetUser tags: - User Account parameters: - name: userId in: path required: true description: Unique User ID for the user to retrieve. schema: type: string example: usr_5pvhvpxyhve6ts31n9x8c2y513 security: - BearerAuth: [] - AccessTokenAuth: [] responses: "200": description: User returned successfully. headers: Cache-Control: description: Caching directive. Always set to `no-store`. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/AdminUserAccountData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 email: ada.admin@example.com firstName: Ada lastName: Lovelace language: en currency: EUR showUnassessedOrSensitiveContent: true tier: ULTIMATE role: ADMIN stripeCustomerId: cus_admin_550e8400e29b41d4a716446655440000 "401": description: Unauthorized - invalid or missing bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the `ADMIN` role and `users:read` capability when delegated. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "404": description: User not found. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND detail: User was not found. "500": description: Internal server error. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: USER_INTERNAL_ERROR patch: summary: Update a user as admin description: "Partially updates a user account for authenticated administrators. Cognito JWTs and Aura Historia access tokens are accepted; delegated access tokens require `users:write`. The caller's persisted user role must be `ADMIN`; this authorization is enforced in the service layer. All request fields are optional, but the request body itself must be present and non-empty. Send only one logical change category per request: profile/preferences fields, `role`, or `tier`. An empty JSON object (`{}`) is accepted and returns the existing user unchanged. Demoting the last active administrator is rejected with `409 CONFLICT`. " operationId: adminPatchUser tags: - User Account parameters: - name: userId in: path required: true description: Unique User ID for the user to update. schema: type: string example: usr_5pvhvpxyhve6ts31n9x8c2y513 security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Partial admin-only user update payload. content: application/json: schema: $ref: "#/components/schemas/PatchAdminUserData" examples: update_role: summary: Promote a user value: role: ADMIN update_tier: summary: Upgrade the tier value: tier: ULTIMATE update_profile: summary: Update profile settings value: firstName: Ada lastName: Lovelace language: en currency: EUR showUnassessedOrSensitiveContent: true responses: "200": description: User updated successfully. headers: Cache-Control: description: Responses are never stored because this is an administrator-only user mutation. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/AdminUserAccountData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 email: ada.admin@example.com firstName: Ada lastName: Lovelace language: en currency: EUR showUnassessedOrSensitiveContent: true tier: ULTIMATE role: ADMIN stripeCustomerId: cus_admin_550e8400e29b41d4a716446655440000 "400": description: Bad request - missing or invalid request body. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Missing request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty invalid_body: summary: Invalid request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE "401": description: Unauthorized - invalid or missing bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the `ADMIN` role; delegated access tokens also require `users:write`. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: This action requires the 'ADMIN' role. "404": description: User not found. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND detail: User with UserId 'usr_5pvhvpxyhve6ts31n9x8c2y513' not found. "409": description: Conflict - the last active administrator cannot be demoted. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: CONFLICT detail: At least one active administrator must remain. "500": description: Internal server error. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR delete: summary: Delete a user as admin description: "Deletes a user account for authenticated administrators. Cognito JWTs and Aura Historia access tokens are accepted; delegated access tokens require `users:write`. The caller's persisted user role must be `ADMIN`; this authorization is enforced in the User service. PostgreSQL synchronously cascades user-owned access tokens, OAuth authorization codes, watchlist entries, saved-search filters and matches, notifications, partnership memberships, and partnership applications. The final active administrator cannot be deleted, including through a self-targeted admin request. " operationId: adminDeleteUser tags: - User Account parameters: - name: userId in: path required: true description: Unique User ID for the user to delete. schema: type: string example: usr_5pvhvpxyhve6ts31n9x8c2y513 security: - BearerAuth: [] - AccessTokenAuth: [] responses: "204": description: User deleted successfully. headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" "400": description: Bad request - the user ID is invalid. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userId type: PATH detail: must be a valid User ID "401": description: Unauthorized - invalid or missing bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the `ADMIN` role; delegated access tokens also require `users:write`. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "404": description: User not found. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND detail: User was not found. "409": description: Conflict - the target state prevents deletion, including removal of the final active administrator. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: CONFLICT detail: At least one active administrator must remain. "503": description: User authorization or persistence is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: USER_TEMPORARILY_UNAVAILABLE "500": description: Internal server error. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: USER_INTERNAL_ERROR /api/v1/admin/users/{userId}/suspension: put: summary: Suspend a user as admin description: | Suspends the explicit target user with an administrator-supplied reason. Cognito JWTs and Aura Historia access tokens are accepted. The caller's persisted user role must be `ADMIN`; delegated Aura Historia access tokens must also have `users:write`. Authorization is enforced in the User service, not only at the HTTP route. `userId` must be a valid User ID. `reason` is required, must not be empty or whitespace-only, and is limited to 1,000 bytes. It is emitted to structured operational logs, so it must not contain tokens, passwords, credentials, or other secrets. Common credential markers are rejected. Suspension is idempotent: a repeated request returns the target's suspended state. The final active administrator cannot be suspended. Once committed, a suspended user is rejected as `401 INVALID_CREDENTIALS` by all later Cognito JWT and Aura access-token authentication. Every response sends `Cache-Control: no-store`. operationId: adminSuspendUser tags: - User Account parameters: - name: userId in: path required: true description: Unique User ID for the user to suspend. schema: type: string example: usr_5pvhvpxyhve6ts31n9x8c2y513 security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/SuspendUserData" example: reason: Repeated policy violations responses: "200": description: User is suspended, including after an idempotent repeat. headers: Cache-Control: description: Responses are never stored because this is an administrator-only user mutation. schema: type: string example: no-store content: application/json: schema: $ref: "#/components/schemas/SuspendUserResponseData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 suspended: true "400": description: Invalid target User ID or missing, empty, oversized, or secret-bearing suspension reason. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_user_id: value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userId type: PATH detail: must be a valid User ID missing_reason: value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Suspension reason is required. invalid_reason: value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Suspension reason is invalid. "401": description: Invalid or missing bearer credentials, including a credential for a suspended user. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: The caller is not an administrator or a delegated credential lacks users:write. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "404": description: Target user was not found. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "409": description: The target is the final active administrator. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: CONFLICT detail: At least one active administrator must remain. "503": description: Authentication, authorization, or user persistence is temporarily unavailable. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: authentication: value: status: 503 title: Service Unavailable error: AUTH_TEMPORARILY_UNAVAILABLE suspension: value: status: 503 title: Service Unavailable error: USER_TEMPORARILY_UNAVAILABLE "500": description: Internal authentication or user persistence failure. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: authentication: value: status: 500 title: Internal Server Error error: AUTH_INTERNAL_ERROR suspension: value: status: 500 title: Internal Server Error error: USER_INTERNAL_ERROR delete: summary: Reactivate a user as admin description: | Removes the durable suspension state for the explicit target user. No request body is accepted. Cognito JWTs and Aura Historia access tokens are accepted. The caller's persisted user role must be `ADMIN`; delegated Aura Historia access tokens must also have `users:write`. Authorization is enforced in the User service, not only at the HTTP route. `userId` must be a valid User ID and the target user must exist. Reactivation is idempotent: a repeated request for an active user returns its active state without another write. The operation changes only suspension state; it preserves the user's profile, tier, role, credentials, and partnership relationships. Once committed, valid existing credentials can authenticate normally again. Every response sends `Cache-Control: no-store`. operationId: adminUnsuspendUser tags: - User Account parameters: - name: userId in: path required: true description: Unique User ID for the user to reactivate. schema: type: string example: usr_5pvhvpxyhve6ts31n9x8c2y513 security: - BearerAuth: [] - AccessTokenAuth: [] responses: "200": description: User is active, including after an idempotent repeat. headers: Cache-Control: description: Responses are never stored because this is an administrator-only user mutation. schema: type: string example: no-store content: application/json: schema: $ref: "#/components/schemas/UnsuspendUserResponseData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 suspended: false "400": description: Invalid target User ID or a nonempty request body. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userId type: PATH detail: must be a valid User ID "401": description: Invalid or missing bearer credentials, including a credential for a suspended user. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: The caller is not an administrator or a delegated credential lacks users:write. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "404": description: Target user was not found. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "409": description: User reactivation conflicts with concurrent state. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: CONFLICT "503": description: Authentication, authorization, or user persistence is temporarily unavailable. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: USER_TEMPORARILY_UNAVAILABLE "500": description: Internal authentication or user persistence failure. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: USER_INTERNAL_ERROR /api/v1/admin/users/{userId}/sessions/revoke: post: summary: Revoke a user's Cognito sessions as admin description: | Invalidates the explicit target user's Cognito sessions with Cognito global sign-out. No request body is accepted. Cognito JWTs and Aura Historia access tokens are accepted. The caller's persisted user role must be `ADMIN`; delegated Aura Historia access tokens must also have `users:write`. Authorization and the target-user check are enforced in the User service, not only at the HTTP route. The PostgreSQL authorization check completes before the external Cognito call. `userId` must be a valid User ID and the target user must exist. Cognito global sign-out is safe to retry: it succeeds when there are no active sessions. The operation does not change the Aura user's profile, tier, role, suspension state, Aura access tokens, or partnerships. Every response sends `Cache-Control: no-store`. operationId: adminRevokeUserSessions tags: - User Account parameters: - name: userId in: path required: true description: Unique User ID for the user whose Cognito sessions are revoked. schema: type: string example: usr_5pvhvpxyhve6ts31n9x8c2y513 security: - BearerAuth: [] - AccessTokenAuth: [] responses: "204": description: Cognito sessions were invalidated, including after a retry with no active sessions. headers: Cache-Control: description: Responses are never stored because this is an administrator-only security operation. schema: type: string example: no-store "400": description: Invalid target User ID. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userId type: PATH detail: must be a valid User ID "401": description: Invalid or missing bearer credentials. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: The caller is not an administrator or a delegated credential lacks users:write. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN "404": description: The target user or corresponding Cognito identity was not found. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "503": description: User authorization, persistence, or Cognito is temporarily unavailable. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: USER_TEMPORARILY_UNAVAILABLE "500": description: Internal user-session revocation failure. headers: Cache-Control: schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: USER_INTERNAL_ERROR /api/v1/admin/users/{userId}/access-tokens: get: summary: List a user's Aura Historia access-token metadata as admin description: | Lists non-secret Aura Historia access-token metadata for the explicit target user. Cognito JWTs and Aura Historia access tokens are accepted. The caller's persisted user role must be `ADMIN`; delegated Aura Historia access tokens must also have `access-tokens:read`. Authorization is enforced in the User service, not only at the HTTP route. `userId` must be a valid User ID and the target user must exist. Expired and current tokens are included. Results use bounded keyset pagination in fixed `created ASC, AccessToken ID ASC` order. Page sizes are clamped to 1–100, with a default of 21. `searchAfter` is a JSON-encoded `[created RFC3339 timestamp, AccessToken ID]` cursor and is omitted on the terminal page. The cursor's creation timestamp is used only for continuation and is not returned as item metadata. Raw token values, token hashes, and masked token values are never returned. operationId: adminListUserAccessTokens tags: - User Account parameters: - name: userId in: path required: true description: Unique User ID for the user whose token metadata is listed. schema: type: string example: usr_5pvhvpxyhve6ts31n9x8c2y513 - name: size in: query required: false description: Requested page size. The server clamps it to 1–100; the default is 21. schema: type: integer format: int64 minimum: 1 maximum: 100 example: 21 - name: searchAfter in: query required: false description: JSON-encoded `[created RFC3339 timestamp, AccessToken ID]` cursor from the previous page. schema: type: string example: '["2026-09-04T12:00:00Z","at_4ck23tcv0meqqrbyjaka24ra6g"]' security: - BearerAuth: [] - AccessTokenAuth: [] responses: "200": description: Secret-free access-token metadata for the target user. headers: Cache-Control: description: Responses are never stored because this is an administrator-only credential read. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/AdminAccessTokenCollectionData" example: items: - userId: usr_5pvhvpxyhve6ts31n9x8c2y513 accessTokenId: at_4ck23tcv0meqqrbyjaka24ra6g name: Incident review token scopes: - users:read origin: User expires: "2026-09-30T00:00:00Z" size: 21 searchAfter: - "2026-09-04T12:00:00Z" - at_4ck23tcv0meqqrbyjaka24ra6g "400": description: Bad request - invalid target User ID, page size, or search-after cursor. headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_user_id: summary: Invalid target user identifier value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userId type: PATH detail: must be a valid User ID invalid_query: summary: Invalid page query value: status: 400 title: Bad Request error: BAD_QUERY_PARAMETER_VALUE source: field: searchAfter type: QUERY "401": description: Unauthorized - invalid or missing bearer credentials. headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - the caller is not an administrator or a delegated credential lacks access-tokens:read. headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "404": description: The target user does not exist. headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND detail: User was not found. "503": description: Access-token authorization or persistence is temporarily unavailable. headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: ACCESS_TOKEN_TEMPORARILY_UNAVAILABLE "500": description: Internal access-token operation failure. headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: ACCESS_TOKEN_INTERNAL_ERROR delete: summary: Revoke all of a user's Aura Historia access tokens as admin description: | Revokes all Aura Historia access tokens owned by the target user in one atomic PostgreSQL transaction. Cognito JWTs and Aura Historia access tokens are accepted. The caller's persisted user role must be `ADMIN`; delegated Aura Historia access tokens must also have `access-tokens:write`. Authorization is enforced in the User service, not only at the HTTP route. `userId` must be a valid User ID and the target user must exist. An existing user with no tokens and a repeated request both return `204 No Content`; a missing target user returns `404 USER_NOT_FOUND`. Deletion is scoped to the target user, leaves unrelated users' tokens untouched, and committed deletion makes the revoked credentials fail authentication. It never reveals raw token values or hashes. operationId: adminDeleteUserAccessTokens tags: - User Account parameters: - name: userId in: path required: true description: Unique User ID for the user whose tokens are revoked. schema: type: string example: usr_5pvhvpxyhve6ts31n9x8c2y513 security: - BearerAuth: [] - AccessTokenAuth: [] responses: "204": description: All access tokens revoked, or no tokens were present for the existing target user. headers: Cache-Control: description: Responses are never stored because this is an administrator-only credential mutation. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" "400": description: Bad request - the user ID is invalid. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userId type: PATH detail: must be a valid User ID "401": description: Unauthorized - invalid or missing bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - the caller is not an administrator or a delegated credential lacks access-tokens:write. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "404": description: The target user does not exist. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND detail: User was not found. "503": description: Access-token authorization or persistence is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: ACCESS_TOKEN_TEMPORARILY_UNAVAILABLE "500": description: Internal access-token operation failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: ACCESS_TOKEN_INTERNAL_ERROR /api/v1/admin/users/{userId}/access-tokens/{accessTokenId}: delete: summary: Revoke a user's Aura Historia access token as admin description: | Revokes one Aura Historia access token for the target user. Cognito JWTs and Aura Historia access tokens are accepted. The caller's persisted user role must be `ADMIN`; delegated Aura Historia access tokens must also have `access-tokens:write`. Authorization is enforced in the User service, not only at the HTTP route. Both `userId` and `accessTokenId` must be valid User and AccessToken IDs, respectively. The database deletion is scoped by both identifiers, so an access-token ID belonging to another user cannot revoke that user's credential. The operation is idempotent: it returns `204 No Content` when the token was deleted, was already absent, or belongs to another user. It never reveals raw token values or hashes. operationId: adminDeleteUserAccessToken tags: - User Account parameters: - name: userId in: path required: true description: Unique User ID for the user whose token is revoked. schema: type: string example: usr_5pvhvpxyhve6ts31n9x8c2y513 - name: accessTokenId in: path required: true description: Unique AccessToken ID for the access token to revoke. schema: type: string example: at_4ck23tcv0meqqrbyjaka24ra6g security: - BearerAuth: [] - AccessTokenAuth: [] responses: "204": description: Access token revoked, or already absent for the target user. headers: Cache-Control: description: Responses are never stored because this is an administrator-only credential mutation. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" "400": description: Bad request - the user ID or access-token ID is invalid. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_user_id: summary: Invalid target user identifier value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: userId type: PATH detail: must be a valid User ID invalid_access_token_id: summary: Invalid access-token identifier value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: accessTokenId type: PATH detail: must be a valid AccessToken ID "401": description: Unauthorized - invalid or missing bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - the caller is not an administrator or a delegated credential lacks access-tokens:write. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "503": description: Access-token authorization or persistence is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: ACCESS_TOKEN_TEMPORARILY_UNAVAILABLE "500": description: Internal access-token operation failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: ACCESS_TOKEN_INTERNAL_ERROR /api/v1/me: delete: summary: Delete authenticated user description: "Permanently deletes the authenticated user's account. The deletion is performed synchronously and the access token is immediately invalidated upon success. Cognito JWTs and Aura Historia access tokens are accepted; delegated access tokens require `users:write`. The last active administrator cannot be deleted. " operationId: deleteUser tags: - User Account security: - BearerAuth: [] - AccessTokenAuth: [] responses: "204": description: User deleted successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" "401": description: Unauthorized - invalid or missing bearer credentials content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "404": description: User not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "409": description: Conflict - the last active administrator cannot be deleted content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: CONFLICT detail: At least one active administrator must remain. "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/account: get: summary: Get user account data description: "Retrieves the authenticated user's account information including email, name, language and currency preferences, the `showUnassessedOrSensitiveContent` preference, the user's subscription tier, and the user's role. Requires valid Cognito JWT authentication. " operationId: getUserAccount tags: - User Account security: - BearerAuth: [] responses: "200": description: User account data retrieved successfully headers: Last-Modified: description: When the user account was last updated schema: type: string format: http-date example: Wed, 01 Jan 2024 12:00:00 GMT Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/OwnUserAccountData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 email: user@example.com firstName: John lastName: Doe language: en currency: EUR showUnassessedOrSensitiveContent: false tier: FREE role: USER created: "2024-01-01T10:00:00Z" updated: "2024-01-01T12:00:00Z" "401": description: Unauthorized - invalid or missing JWT token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: UNAUTHORIZED "404": description: User not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR patch: summary: Update user account data description: "Updates the authenticated user's account information. All fields in the request body are optional - only provided fields will be updated. The user's `role` is returned in the response but cannot be updated through this endpoint. Returns the updated user account data. Requires valid Cognito JWT authentication. " operationId: updateUserAccount tags: - User Account security: - BearerAuth: [] requestBody: required: true description: "Partial user account update data. All fields are optional - only provided fields will be updated. " content: application/json: schema: $ref: "#/components/schemas/PatchUserAccountData" examples: update_all: summary: Update all fields value: firstName: Jane lastName: Smith language: de currency: USD showUnassessedOrSensitiveContent: true update_name_only: summary: Update name only value: firstName: Jane lastName: Smith update_preferences_only: summary: Update language and currency only value: language: fr currency: GBP update_content_visibility_preference_only: summary: Update content visibility preference only value: showUnassessedOrSensitiveContent: true responses: "200": description: User account updated successfully headers: Last-Modified: description: When the user account was last updated schema: type: string format: http-date example: Wed, 01 Jan 2024 12:30:00 GMT Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/OwnUserAccountData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 email: jane.smith@example.com firstName: Jane lastName: Smith language: de currency: USD showUnassessedOrSensitiveContent: true tier: FREE role: USER created: "2024-01-01T10:00:00Z" updated: "2024-01-01T12:30:00Z" "400": description: Bad request - invalid request body content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Missing request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty invalid_json: summary: Invalid JSON format value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Invalid JSON format "401": description: Unauthorized - invalid or missing JWT token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: UNAUTHORIZED "404": description: User not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/access-tokens: post: summary: Create an Aura Historia access token description: "Creates a new Aura Historia access token for the authenticated user. The response includes the plaintext bearer token once. List, get, and update responses contain only secret-free metadata and never return the bearer token again. Accepts Cognito access JWTs or Aura Historia opaque bearer access tokens. Aura Historia access tokens require the delegated `access-tokens:write` capability. " operationId: postMyAccessToken tags: - User Account security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Access-token creation payload. content: application/json: schema: $ref: "#/components/schemas/PostAccessTokenData" example: name: Partner product sync scopes: - product-listings:write expires: "2026-06-30T00:00:00Z" responses: "201": description: Access token created successfully headers: Cache-Control: description: Caching directive. Always set to `no-store`. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/CreatedAccessTokenData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 accessTokenId: at_4ck23tcv0meqqrbyjaka24ra6g accessToken: aurahistoria_abcdefghijk_abcdefghijklmnopqrstuvwxyz1234567 "400": description: Bad request - missing, empty, or invalid JSON body content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Missing request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Request body is required. invalid_scope: summary: Unsupported access-token scope value value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: "Unsupported scope 'unsupported:scope'." "401": description: Unauthorized - invalid or missing bearer credentials content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS source: field: Authorization type: HEADER detail: Bearer token is invalid. "404": description: User not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR get: summary: List Aura Historia access tokens description: "Lists all of the authenticated user's persisted Aura Historia access tokens, including expired and current tokens. The response contains secret-free metadata only. It does not return plaintext or masked token values. Accepts Cognito access JWTs or Aura Historia opaque bearer access tokens. Aura Historia access tokens require the delegated `access-tokens:read` capability. " operationId: getMyAccessTokens tags: - User Account security: - BearerAuth: [] - AccessTokenAuth: [] responses: "200": description: Access tokens retrieved successfully headers: Cache-Control: description: Caching directive. Always set to `no-store`. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: type: array items: $ref: "#/components/schemas/OwnAccessTokenData" examples: one_token: summary: One persisted access token value: - userId: usr_5pvhvpxyhve6ts31n9x8c2y513 accessTokenId: at_4ck23tcv0meqqrbyjaka24ra6g name: Partner product sync scopes: - product-listings:write origin: User expires: "2026-06-30T00:00:00Z" no_tokens: summary: No persisted access tokens exist value: [] "401": description: Unauthorized - invalid or missing bearer credentials content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS source: field: Authorization type: HEADER detail: Bearer token is invalid. "404": description: User not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR patch: summary: Update an Aura Historia access token description: "Updates metadata for one access token owned by the authenticated user. Omitted properties remain unchanged; `expires: null` clears expiry. `name` and `scopes` reject `null`; use `scopes: []` to clear scopes. The response contains secret-free metadata only and never returns plaintext or masked token values. Accepts Cognito access JWTs or Aura Historia opaque bearer access tokens. Aura Historia access tokens require the delegated `access-tokens:write` capability. " operationId: patchMyAccessToken tags: - User Account security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true description: Partial access-token update payload. content: application/json: schema: $ref: "#/components/schemas/PatchAccessTokenData" example: accessTokenId: at_4ck23tcv0meqqrbyjaka24ra6g name: Renamed partner sync token scopes: - product-listings:write expires: "2026-07-31T00:00:00Z" responses: "200": description: Access token updated successfully headers: Cache-Control: description: Caching directive. Always set to `no-store`. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/OwnAccessTokenData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 accessTokenId: at_4ck23tcv0meqqrbyjaka24ra6g name: Renamed partner sync token scopes: - product-listings:write origin: User expires: "2026-07-31T00:00:00Z" "400": description: Bad request - missing, empty, or invalid JSON body content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Missing request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Request body is required. invalid_access_token_id: summary: Invalid access token identifier in request body value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: accessTokenId type: BODY detail: must be a valid AccessToken ID "401": description: Unauthorized - invalid or missing bearer credentials content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS source: field: Authorization type: HEADER detail: Bearer token is invalid. "404": description: Access token not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: ACCESS_TOKEN_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/access-tokens/{accessTokenId}: get: summary: Get one Aura Historia access token description: "Retrieves one persisted Aura Historia access token owned by the authenticated user, including expired and current tokens. The response contains secret-free metadata only. It does not return plaintext or masked token values. Accepts Cognito access JWTs or Aura Historia opaque bearer access tokens. Aura Historia access tokens require the delegated `access-tokens:read` capability. " operationId: getMyAccessToken tags: - User Account security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: accessTokenId in: path required: true description: Unique identifier of the access token schema: type: string example: at_4ck23tcv0meqqrbyjaka24ra6g responses: "200": description: Access token retrieved successfully headers: Cache-Control: description: Caching directive. Always set to `no-store`. schema: type: string example: no-store Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/OwnAccessTokenData" example: userId: usr_5pvhvpxyhve6ts31n9x8c2y513 accessTokenId: at_4ck23tcv0meqqrbyjaka24ra6g name: Partner product sync scopes: - product-listings:write origin: User expires: "2026-06-30T00:00:00Z" "400": description: Bad request - invalid or missing access-token path parameter content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_access_token_id: summary: Missing access-token path parameter value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: accessTokenId type: PATH detail: Missing field 'accessTokenId'. invalid_access_token_id: summary: Invalid access-token identifier value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: accessTokenId type: PATH detail: must be a valid AccessToken ID "401": description: Unauthorized - invalid or missing bearer credentials content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS source: field: Authorization type: HEADER detail: Bearer token is invalid. "404": description: Access token not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: ACCESS_TOKEN_NOT_FOUND "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR delete: summary: Delete an Aura Historia access token description: "Deletes one access token owned by the authenticated user. The token to delete is identified by the required `{accessTokenId}` path parameter. Cognito JWTs and Aura Historia access tokens are accepted; delegated access tokens require `access-tokens:write`. The operation is idempotent: an already-revoked or missing token is a successful no-op and returns `204 No Content`. " operationId: deleteMyAccessToken tags: - User Account security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: accessTokenId in: path required: true description: Unique identifier of the access token to delete schema: type: string example: at_4ck23tcv0meqqrbyjaka24ra6g responses: "204": description: Access token deleted successfully, or already absent for the authenticated user headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" "400": description: Bad request - invalid or missing access-token path parameter content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_access_token_id: summary: Missing access-token path parameter value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: accessTokenId type: PATH detail: Missing field 'accessTokenId'. invalid_access_token_id: summary: Invalid access-token identifier value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: accessTokenId type: PATH detail: must be a valid AccessToken ID "401": description: Unauthorized - invalid or missing bearer credentials content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS source: field: Authorization type: HEADER detail: Bearer token is invalid. "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/billing/checkout: post: summary: Create Stripe checkout session description: "Creates a hosted Stripe Checkout session for the authenticated user to start a subscription. The request body selects the desired subscription plan and billing cycle. The backend first creates and persists a Stripe customer for the user, then creates a subscription-mode Checkout session for that customer. Stripe and PostgreSQL are separate systems; an association remains persisted if later session creation fails. This endpoint can only be used when the user does not already have a `stripe_customer_id`. Requires Cognito JWT or Aura Historia access-token authentication. Delegated access tokens require `users:read`. " operationId: postBillingCheckout tags: - Billing security: - BearerAuth: [] requestBody: required: true description: Desired subscription plan and billing cycle for the new Stripe checkout session. content: application/json: schema: $ref: "#/components/schemas/PostBillingCheckoutData" examples: pro_monthly: summary: Create a monthly Pro checkout session value: plan: PRO cycle: MONTHLY ultimate_yearly: summary: Create a yearly Ultimate checkout session value: plan: ULTIMATE cycle: YEARLY responses: "201": description: Checkout session created successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/BillingSessionUrlData" example: url: https://checkout.stripe.com/c/pay/cs_test_123 "400": description: Bad request - request body is missing, empty, malformed JSON, or contains unsupported enum values content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Request body is absent or empty value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty invalid_plan: summary: Unsupported billing plan value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: unknown variant `ENTERPRISE`, expected `PRO` or `ULTIMATE` at line 1 column 20 "401": description: Unauthorized - invalid or missing JWT token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: UNAUTHORIZED "404": description: User not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "409": description: Conflict - the authenticated user already has a Stripe customer record content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: STRIPE_CUSTOMER_ALREADY_EXISTS detail: User has already created a Stripe customer; use the customer-portal endpoint instead "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/billing/portal: post: summary: Create Stripe billing portal session description: "Creates a hosted Stripe customer-portal session for the authenticated user. This endpoint does not accept a request body. It can only be used when the user already has a persisted `stripe_customer_id`. Requires Cognito JWT or Aura Historia access-token authentication. Delegated access tokens require `users:read`. " operationId: postBillingPortal tags: - Billing security: - BearerAuth: [] responses: "201": description: Billing portal session created successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/BillingSessionUrlData" example: url: https://billing.stripe.com/p/session/test_123 "401": description: Unauthorized - invalid or missing JWT token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: UNAUTHORIZED "404": description: User not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "422": description: Unprocessable Content - the authenticated user has no Stripe customer record yet content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 422 title: Unprocessable Content error: STRIPE_CUSTOMER_DOES_NOT_EXIST detail: User has never had a Stripe subscription; no customer-portal session can be created "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/billing/manage: post: summary: Create Stripe billing management session description: "Creates a hosted Stripe billing session for the authenticated user through a single entrypoint. - Users with tier `FREE` receive a Stripe Checkout session for the requested `plan` and `cycle`. - Users with tier `PRO` or `ULTIMATE` receive a Stripe customer-portal session instead. The request body is required for all callers and must contain supported billing enum values. For free users, the backend uses the provided `plan` and `cycle` to select the configured Stripe price and creates a Stripe customer first when none exists yet. For paid users, the backend still validates that the body is present and well-formed, but returns a portal session based on the stored Stripe customer rather than purchasing a new plan. Requires Cognito JWT or Aura Historia access-token authentication. Delegated access tokens require `users:read`. " operationId: postBillingManage tags: - Billing security: - BearerAuth: [] requestBody: required: true description: Desired subscription plan and billing cycle. Required for all callers. content: application/json: schema: $ref: "#/components/schemas/PostBillingCheckoutData" examples: pro_monthly: summary: Valid request body for a free user upgrading to Pro monthly value: plan: PRO cycle: MONTHLY ultimate_yearly: summary: Valid request body for a free user upgrading to Ultimate yearly value: plan: ULTIMATE cycle: YEARLY responses: "201": description: Billing management session created successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/BillingSessionUrlData" examples: checkout_session: summary: Free user receives a Stripe Checkout session URL value: url: https://checkout.stripe.com/c/pay/cs_test_manage_free portal_session: summary: Paid user receives a Stripe customer-portal session URL value: url: https://billing.stripe.com/p/session/manage_paid "400": description: Bad request - request body is missing, empty, malformed JSON, or contains unsupported enum values content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Request body is absent or empty value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty invalid_plan: summary: Unsupported billing plan value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: unknown variant `ENTERPRISE`, expected `PRO` or `ULTIMATE` at line 1 column 20 "401": description: Unauthorized - invalid or missing JWT token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: UNAUTHORIZED "404": description: User not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: USER_NOT_FOUND "422": description: Unprocessable Content - the authenticated paid user has no Stripe customer record yet content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 422 title: Unprocessable Content error: STRIPE_CUSTOMER_DOES_NOT_EXIST detail: User has never had a Stripe subscription; no customer-portal session can be created "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/watchlist/{productListingId}: delete: summary: Remove product from watchlist description: "Removes a specific product from the authenticated user's watchlist. Returns a 204 No Content response on success. Requires valid Cognito JWT authentication. " operationId: deleteWatchlistProduct tags: - Watchlist parameters: - name: productListingId in: path required: true description: Unique identifier of the product schema: type: string example: pl_5xdb465tg1enarx2knf04mxbxj security: - BearerAuth: [] responses: "204": description: Product removed from watchlist successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" "400": description: Bad request - invalid parameters content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_product_id: summary: Missing product ID value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: productListingId type: PATH invalid_object_id: summary: Invalid product ID format value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: productListingId type: PATH detail: must be a valid ProductListing ID "401": description: Unauthorized - invalid or missing JWT token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: UNAUTHORIZED "404": description: Watchlist entry not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: WATCHLIST_ENTRY_NOT_FOUND "409": description: Watchlist entry was changed concurrently content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: CONFLICT detail: Watchlist entry was changed concurrently. "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR patch: summary: Update watchlist product settings description: "Updates settings for a specific watchlist product (e.g., toggle notifications or manually activate/deactivate the watchlist entry). Returns the full personalized product data after applying the update. Requires valid Cognito JWT authentication. " operationId: patchWatchlistProduct tags: - Watchlist parameters: - name: productListingId in: path required: true description: Unique identifier of the product schema: type: string example: pl_5xdb465tg1enarx2knf04mxbxj - name: language in: query required: false description: "Preferred language for localized content in the response. Defaults to `en` when omitted. " schema: $ref: "#/components/schemas/LanguageData" example: de - name: currency in: query required: false description: Currency for price display in the response. schema: $ref: "#/components/schemas/CurrencyData" example: EUR security: - BearerAuth: [] requestBody: required: true description: Patch object containing fields to update content: application/json: schema: $ref: "#/components/schemas/WatchlistProductPatch" examples: enable_notifications: summary: Enable notifications value: notifications: true disable_notifications: summary: Disable notifications value: notifications: false deactivate_watchlist_entry: summary: Deactivate this watchlist entry manually value: state: INACTIVE_BY_USER reactivate_watchlist_entry: summary: Reactivate this watchlist entry value: state: ACTIVE responses: "200": description: Watchlist product updated successfully headers: Access-Control-Allow-Origin: description: CORS header schema: type: string example: "*" content: application/json: schema: $ref: "#/components/schemas/PersonalizedProductListingDetailsData" example: item: productListingId: pl_5xdb465tg1enarx2knf04mxbxj productListingTitleSlugId: smartphone-case-a1b2c3 eventId: evt_69wh1chr82fen9vvyk6n3mh80m source: listingSourceId: ls_6rd827eqfefsva9teecmwa3ate name: Tech Store slugId: tech-store sourceListingId: 6ba7b810-9dad-11d1-80b4-00c04fd430c8 title: text: Smartphone Case language: en price: offer: currency: EUR amount: 2999 estimate: min: currency: EUR amount: 2700 max: currency: EUR amount: 3300 availability: IN_STOCK url: https://tech-store.com/smartphone-case viewUrl: https://tech-store.com/smartphone-case?utm_source=aura_historia&utm_medium=referral images: - url: https://tech-store.com/images/case-1.jpg contentPolicy: decision: ALLOWED created: "2024-01-01T10:00:00Z" updated: "2024-01-01T12:00:00Z" userState: watchlist: watching: true notifications: true contentVisibility: showUnassessedOrSensitiveContent: false notification: unseenNotificationIds: [] "400": description: Bad request - invalid parameters or body content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_product_id: summary: Missing product ID value: status: 400 title: Bad Request error: BAD_PATH_PARAMETER_VALUE source: field: productListingId type: PATH invalid_object_id: summary: Invalid product ID format value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: productListingId type: PATH detail: must be a valid ProductListing ID missing_body: summary: Missing request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Body cannot be empty invalid_body: summary: Invalid request body format value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: Invalid JSON format "401": description: Unauthorized - invalid or missing JWT token content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: UNAUTHORIZED "404": description: Watchlist entry or ProductListing not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: watchlist_entry_not_found: value: status: 404 title: Not Found error: WATCHLIST_ENTRY_NOT_FOUND product_listing_not_found: value: status: 404 title: Not Found error: PRODUCT_LISTING_NOT_FOUND "422": description: Unprocessable Entity - watchlist quota exceeded during reactivation content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 422 title: Unprocessable Content error: WATCHLIST_QUOTA_EXCEEDED detail: Exceeded the maximum amount of watchlist entries. There are already 20/20 active watchlist entries occupied. "409": description: Watchlist entry was changed concurrently, or a withdrawn ProductListing cannot be reactivated content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: concurrency_conflict: value: status: 409 title: Conflict error: CONFLICT detail: Watchlist entry was changed concurrently. product_listing_unavailable: value: status: 409 title: Conflict error: PRODUCT_LISTING_UNAVAILABLE "500": description: Internal server error content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: INTERNAL_SERVER_ERROR /api/v1/me/notifications: get: summary: List user notifications description: "Delegated Aura access tokens require `notifications:read`; missing scope returns `403 FORBIDDEN`. Retrieves the authenticated user’s canonical notifications in newest-first order. Watchlist price-change notifications preserve each event’s immutable source currency; no FX conversion is applied from the user’s preferences. Product image URLs are presented according to the authenticated user’s `showUnassessedOrSensitiveContent` preference. " operationId: listNotifications tags: - Notifications parameters: - name: language in: query required: false schema: $ref: "#/components/schemas/LanguageData" - name: size in: query required: false schema: type: integer minimum: 1 maximum: 100 default: 21 - name: searchAfter in: query required: false description: Opaque JSON `[created RFC3339 timestamp, Notification ID]` cursor returned by the prior page. schema: type: string security: - BearerAuth: [] - AccessTokenAuth: [] responses: "200": description: Notifications retrieved successfully. headers: Cache-Control: schema: type: string example: no-store content: application/json: schema: $ref: "#/components/schemas/NotificationCollectionData" "400": description: Bad request content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Forbidden - required delegated scope missing content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Invalid or missing bearer credential content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Notifications are temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" patch: summary: Update selected notification seen states description: Delegated Aura access tokens require `notifications:write`; missing scope returns `403 FORBIDDEN`. Updates the seen state for the explicit canonical notification IDs in the request body. operationId: updateNotificationsSeen tags: - Notifications security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateNotificationsSeenData" responses: "204": description: Selected notifications updated. "400": description: Bad request content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Forbidden - required delegated scope missing content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Invalid or missing bearer credential content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Notifications are temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" delete: summary: Delete all notifications description: Delegated Aura access tokens require `notifications:write`; missing scope returns `403 FORBIDDEN`. operationId: deleteNotifications tags: - Notifications security: - BearerAuth: [] - AccessTokenAuth: [] responses: "204": description: Notifications deleted. "403": description: Forbidden - required delegated scope missing content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Invalid or missing bearer credential content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Notifications are temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" /api/v1/me/notifications/all: patch: summary: Update all notification seen states description: Delegated Aura access tokens require `notifications:write`; missing scope returns `403 FORBIDDEN`. operationId: updateAllNotificationsSeen tags: - Notifications security: - BearerAuth: [] - AccessTokenAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateNotificationSeenData" responses: "204": description: Notifications updated. "400": description: Bad request content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Forbidden - required delegated scope missing content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Invalid or missing bearer credential content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Notifications are temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" /api/v1/me/notifications/{notificationId}: patch: summary: Update one notification seen state description: Delegated Aura access tokens require `notifications:write`; missing scope returns `403 FORBIDDEN`. operationId: updateNotificationSeen tags: - Notifications security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: notificationId in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateNotificationSeenData" responses: "204": description: Notification updated. "400": description: Bad request content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Forbidden - required delegated scope missing content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Invalid or missing bearer credential content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Notifications are temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: Notification not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" delete: summary: Delete one notification description: Delegated Aura access tokens require `notifications:write`; missing scope returns `403 FORBIDDEN`. operationId: deleteNotification tags: - Notifications security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: notificationId in: path required: true schema: type: string responses: "204": description: Notification deleted. "400": description: Bad request content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Forbidden - required delegated scope missing content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Invalid or missing bearer credential content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Notifications are temporarily unavailable content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: Notification not found content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" /api/v1/newsletter-subscriptions: put: summary: Request newsletter confirmation description: | Requests double opt-in confirmation for the submitted email and optional profile. The endpoint accepts anonymous requests. An optional Cognito JWT or Aura Historia access-token bearer credential may be supplied; an invalid supplied credential returns 401. For an authenticated user, omitted profile values can fall back to that user's stored profile, but the credential never proves ownership of the submitted mailbox and never skips confirmation, including when the submitted address exactly matches the caller's account email. The body is limited to 8 KiB. Every result is `Cache-Control: no-store`. Empty 204 means the request was handled, including when rate suppression applies. It does not reveal account or pending-challenge state, confirm a subscription, or mean that email was delivered or Loops was called. Loops synchronization occurs asynchronously after confirmation. operationId: putNewsletterSubscription tags: - Newsletter security: - BearerAuth: [] - {} requestBody: required: true description: Newsletter confirmation request data. content: application/json: schema: $ref: "#/components/schemas/PutNewsletterSubscriptionData" examples: minimal: summary: Request confirmation with email only value: email: collector@example.com complete: summary: Request confirmation with explicit profile values value: email: collector@example.com firstName: Ada lastName: Lovelace language: en currency: EUR responses: "204": description: Confirmation request handled. The requested mailbox may be pending, already confirmed, or rate suppressed. headers: Cache-Control: description: Shared caching is disabled for the response. schema: type: string example: no-store "400": description: Missing, malformed, oversized, or invalid request body. headers: Cache-Control: description: Shared caching is disabled for the response. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: missing_body: summary: Missing request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE invalid_body: summary: Invalid request body value: status: 400 title: Bad Request error: BAD_BODY_VALUE "401": description: A supplied bearer credential is invalid. headers: Cache-Control: description: Shared caching is disabled for the response. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "503": description: Newsletter persistence, confirmation-template retrieval, or SES is temporarily unavailable, SES throttling was rejected, or SES acceptance is ambiguous. headers: Cache-Control: description: Shared caching is disabled for the response. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: NEWSLETTER_TEMPORARILY_UNAVAILABLE "500": description: Internal/configuration failure, including a permanent definite SES rejection. headers: Cache-Control: description: Shared caching is disabled for the response. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: NEWSLETTER_INTERNAL_ERROR /api/v1/newsletter-subscriptions/confirm: post: summary: Confirm a newsletter subscription description: | Confirms the newsletter subscription using the bearer capability in the JSON body. This anonymous route accepts no Aura bearer credential. The body is limited to 8 KiB and the token to 512 bytes. Every result is `Cache-Control: no-store`. Empty 204 means the C09 confirmation, consent-state, and asynchronous Loops intent transaction committed; replaying a retained confirmed token also returns 204 without another grant. It does not mean Loops accepted or applied the later provider update. Tokens are not accepted in paths, query parameters, or GET requests. operationId: confirmNewsletterSubscription tags: - Newsletter security: [] requestBody: required: true description: The opaque confirmation capability. content: application/json: schema: $ref: "#/components/schemas/ConfirmNewsletterSubscriptionData" example: token: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" responses: "204": description: Confirmation committed, or an already confirmed token was replayed. headers: Cache-Control: description: Shared caching is disabled for the response. schema: type: string example: no-store "400": description: Malformed, oversized, or wrong-shape body, or one generic invalid, unknown, expired, or invalidated confirmation result. headers: Cache-Control: description: Shared caching is disabled for the response. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: malformed_body: summary: Body does not match the token-only schema value: status: 400 title: Bad Request error: BAD_BODY_VALUE invalid_confirmation: summary: Invalid or unavailable confirmation capability value: status: 400 title: Bad Request error: NEWSLETTER_CONFIRMATION_INVALID "503": description: Newsletter confirmation persistence is temporarily unavailable. headers: Cache-Control: description: Shared caching is disabled for the response. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: NEWSLETTER_TEMPORARILY_UNAVAILABLE "500": description: Internal confirmation-state failure. headers: Cache-Control: description: Shared caching is disabled for the response. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: NEWSLETTER_INTERNAL_ERROR /api/v1/admin/listing-sources/{listingSourceId}: get: summary: Get a ListingSource as admin description: | Delegated Aura access tokens require `listing-sources:read`; missing scope returns `403 FORBIDDEN`. Gets one ListingSource for an authenticated administrator. `listingSourceId` must be a valid ListingSource ID. The response uses the canonical ListingSource detail representation and never exposes provider credentials, webhook secrets, or crawler-local configuration. operationId: adminGetListingSource tags: - ListingSources parameters: - name: listingSourceId in: path required: true schema: type: string responses: "200": description: ListingSource returned successfully. content: application/json: schema: $ref: "#/components/schemas/ListingSourceData" "400": description: Bad request - invalid ListingSource ID. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Unauthorized - missing or invalid bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Forbidden - this endpoint requires the ADMIN role. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: ListingSource was not found. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "500": description: Internal authentication or ListingSource detail failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Authentication, authorization, or ListingSource detail is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" security: - BearerAuth: [] - AccessTokenAuth: [] patch: summary: Update a ListingSource as admin description: | Delegated Aura access tokens require `listing-sources:write`; missing scope returns `403 FORBIDDEN`. Updates one ListingSource for an authenticated administrator. `listingSourceId` must be a valid ListingSource ID. Omitted members remain unchanged; `null` clears only `url`, `image`, and `referralConfiguration`. `name` and `ingestionConfiguration` are non-nullable and cannot be cleared. Supplying `ingestionConfiguration` replaces the whole configuration list and its methods must match the ListingSource ingestion methods. A WooCommerce entry may omit `webhookSecret` only when WooCommerce is already configured; omission preserves the existing secret, a string rotates it, and `null` is invalid. An empty object is a valid no-op PATCH; an empty HTTP body is invalid. Renaming a ListingSource never changes its immutable slug. The response contains only the stable ListingSource ID and slug. WooCommerce webhook secrets are write-only: they are never returned or logged. operationId: adminUpdateListingSource tags: - ListingSources security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: listingSourceId in: path required: true description: Stable ListingSource identifier. schema: type: string example: ls_6rd827eqfefsva9teecmwa3ate requestBody: required: true description: ListingSource patch. Omit unchanged members; null clears only documented nullable members. content: application/json: schema: $ref: "#/components/schemas/UpdateListingSourceData" examples: update: summary: Update name, ingestion configuration, and presentation value: name: Antiques and More ingestionConfiguration: - type: WOOCOMMERCE currency: EUR language: en url: https://antiques.example/ image: https://antiques.example/image.jpg referralConfiguration: type: PARTNERIZE camref: campaign123 clear_values: summary: Clear nullable ListingSource values value: url: null image: null referralConfiguration: null no_op_patch: summary: Leave the ListingSource unchanged value: {} responses: "200": description: ListingSource updated successfully. content: application/json: schema: $ref: "#/components/schemas/ListingSourceReferenceData" example: listingSourceId: ls_6rd827eqfefsva9teecmwa3ate listingSourceSlugId: antiques-and-more-550e8400-e29b-41d4-a716-446655440000 "400": description: Bad request - invalid ListingSource ID, empty/malformed body, invalid values, or ingestion configuration mismatch. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" examples: invalid_listing_source_id: summary: Invalid ListingSource ID value: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: listingSourceId type: PATH detail: must be a valid ListingSource ID invalid_patch: summary: Invalid patch value value: status: 400 title: Bad Request error: BAD_BODY_VALUE detail: ListingSource ingestion configuration is invalid. "401": description: Unauthorized - missing or invalid bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "403": description: Forbidden - this endpoint requires the ADMIN role. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 403 title: Forbidden error: FORBIDDEN detail: Operation is not permitted. "404": description: ListingSource was not found. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: LISTING_SOURCE_NOT_FOUND detail: Listing source was not found. "409": description: Conflict - the ListingSource was changed concurrently or conflicts with current provider state. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 409 title: Conflict error: CONFLICT detail: Listing source conflicts with current state. "503": description: Authentication, authorization, or ListingSource persistence is temporarily unavailable. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: LISTING_SOURCE_TEMPORARILY_UNAVAILABLE "500": description: Internal authentication or ListingSource update failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: LISTING_SOURCE_INTERNAL_ERROR delete: summary: Delete an unused ListingSource as admin description: | Delegated Aura access tokens require `listing-sources:write`; missing scope returns `403 FORBIDDEN`. Physically removes a ListingSource only when it has no ProductListings, raw-ingestion streams, approved PartnershipApplication reference, or retained existing-source proposal. The committed transaction explicitly removes its Partnership grants and owned ingestion configuration, including provider/webhook secrets. Enabled `WEB_CRAWL` is not a blocker: every new spider or scraper pass refreshes authoritative ListingSource scope before candidate selection, and a failed refresh skips that pass. Already-running work can race with deletion; the business raw-capture fence discards that missing-source result without recreating state. This operation does not retire or purge a used source. A repeated delete returns `404`. operationId: adminDeleteListingSource tags: - ListingSources security: - BearerAuth: [] - AccessTokenAuth: [] parameters: - name: listingSourceId in: path required: true schema: type: string responses: "204": description: ListingSource removed. The response body is empty. headers: Cache-Control: schema: type: string example: no-store "400": description: Invalid ListingSource ID (`INVALID_OBJECT_ID`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "401": description: Missing or invalid bearer credentials. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "403": description: Administrator authority is required (`FORBIDDEN`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "404": description: ListingSource was not found (`LISTING_SOURCE_NOT_FOUND`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "409": description: A protected dependency or concurrent mutation blocks deletion (`CONFLICT`). content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "500": description: Invalid persisted state or internal deletion failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" "503": description: Temporary authorization or persistence failure. content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" /api/v1/oauth/clients/{clientId}: get: summary: Get OAuth client metadata for consent description: | Reads the authoritative registered metadata for one OAuth client before the user begins or completes consent. This is a read only: it does not record consent, issue an authorization code or token, or grant privileges. Any signed-in ordinary user can read a registered client without the ADMIN role, client ownership, an existing client token, or a source partnership. Only a Cognito access JWT is accepted through `BearerAuth`; Cognito ID tokens, Aura opaque access tokens, and client-secret credentials are rejected. Centralized account restrictions continue to apply. Redirect URIs and allowed scopes are returned exactly as registered; `scope: []` means the client has no allowed scopes and does not imply user consent. `/api/v1/oauth/authorize` remains authoritative and revalidates registration, exact redirect URI, requested-scope subset, and S256 PKCE before issuing a code. Every success and error response uses `Cache-Control: no-store`. operationId: getOAuthConsentClient tags: - OAuth security: - BearerAuth: [] parameters: - name: clientId in: path required: true description: Canonical OAuthClient ID (`oc_` TypeID). schema: type: string example: oc_7b0gwc1x49e0mvbt3tfexfqgb5 responses: "200": description: Secret-free registered consent metadata retrieved successfully. headers: Cache-Control: description: Success responses are never stored. schema: type: string example: no-store content: application/json: schema: $ref: "#/components/schemas/OAuthClientConsentMetadataData" example: client_id: oc_7b0gwc1x49e0mvbt3tfexfqgb5 client_name: Aura Historia WooCommerce tos_uri: https://integration.example/terms policy_uri: https://integration.example/privacy client_uri: https://integration.example logo_uri: https://integration.example/logo.png redirect_uris: - https://stage.aura-historia.com/api/oauth/client/redirect-broker/woocommerce scope: - product-listings:write "400": description: Malformed or non-canonical OAuthClient ID (`INVALID_OBJECT_ID`); the problem source has `field` `clientId` and `type` `PATH`. headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 400 title: Bad Request error: INVALID_OBJECT_ID source: field: clientId type: PATH detail: must be a valid OAuthClient ID "401": description: Missing, invalid, expired, or unsupported bearer credentials, including ID tokens, opaque Aura tokens, and client-secret credentials (`INVALID_CREDENTIALS`). headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 401 title: Unauthorized error: INVALID_CREDENTIALS "404": description: Well-formed OAuthClient ID has no current registration (`OAUTH_CLIENT_NOT_FOUND`). headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 404 title: Not Found error: OAUTH_CLIENT_NOT_FOUND detail: OAuth client not found. "500": description: Internal OAuth metadata read failure (`OAUTH_INTERNAL_ERROR`); internal details are not returned. headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 500 title: Internal Server Error error: OAUTH_INTERNAL_ERROR "503": description: Temporary metadata reader failure (`OAUTH_TEMPORARILY_UNAVAILABLE`) or temporary authentication dependency failure (`AUTH_TEMPORARILY_UNAVAILABLE`); no database or credential details are returned. headers: Cache-Control: description: Error responses are never stored. schema: type: string example: no-store content: application/problem+json: schema: $ref: "#/components/schemas/ApiError" example: status: 503 title: Service Unavailable error: OAUTH_TEMPORARILY_UNAVAILABLE /api/v1/oauth/authorize: get: summary: OAuth2 authorization endpoint description: "Starts the OAuth2 authorization code flow (RFC 6749 §4.1). The authenticated user (resource owner) grants the requesting OAuth client access to their Aura Historia account. PKCE (RFC 7636) with `S256` is required for all requests. On success the endpoint redirects (302) to the `redirect_uri` appending `code` and, if supplied, `state` as query parameters. The single-use authorization code must be exchanged for an access token via `POST /api/v1/oauth/token` before it expires. A delegated caller must have `access-tokens:write` and every requested OAuth scope. " operationId: oauthAuthorize tags: - OAuth security: - BearerAuth: [] parameters: - name: response_type in: query required: true description: OAuth response type. Must be `code`. schema: type: string enum: - code example: code - name: client_id in: query required: true description: Canonical OAuthClient ID. schema: type: string example: oc_7b0gwc1x49e0mvbt3tfexfqgb5 - name: redirect_uri in: query required: true description: Redirect URI registered for the OAuth client. Must exactly match one of the client's registered redirect URIs. schema: type: string format: uri example: https://client.example/callback - name: scope in: query required: false description: Space-separated list of requested scopes. Must be a subset of the client's allowed scopes. schema: type: string example: product-listings:write - name: state in: query required: false description: Opaque client state value. Returned unchanged in the redirect to prevent CSRF attacks. schema: type: string example: xyz - name: code_challenge in: query required: true description: PKCE code challenge. Must be the base64url-encoded SHA256 hash of the `code_verifier` (S256 method). schema: type: string example: E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM - name: code_challenge_method in: query required: true description: PKCE challenge method. Must be `S256`. schema: type: string enum: - S256 example: S256 responses: "302": description: "Authorization successful. The user-agent is redirected to `redirect_uri` with the one-time authorization `code` and the original `state` (if supplied) appended as query parameters, e.g. `https://client.example/callback?code=&state=`.
"
headers:
Location:
description: Redirect URL containing the authorization `code` and optional `state`.
schema:
type: string
format: uri
example: https://client.example/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
Cache-Control:
description: Always set to `no-store`.
schema:
type: string
example: no-store
"400":
description: Bad request — a required query parameter is missing, malformed, or has an unsupported value.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
missing_response_type:
summary: Missing response_type query parameter
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: response_type
type: QUERY
detail: Missing query parameter response_type
unsupported_response_type:
summary: Unsupported response_type value
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: response_type
type: QUERY
detail: Unsupported response_type 'token'
missing_code_challenge:
summary: Missing code_challenge query parameter
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: code_challenge
type: QUERY
detail: Missing query parameter code_challenge
unsupported_code_challenge_method:
summary: Unsupported code_challenge_method
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: code_challenge_method
type: QUERY
detail: Unsupported code_challenge_method 'plain'
invalid_scope:
summary: Requested scope not allowed for client
value:
status: 400
title: Bad Request
error: OAUTH_INVALID_SCOPE
source:
field: scope
type: QUERY
detail: Requested scope is not allowed for client.
invalid_redirect_uri:
summary: Redirect URI not registered for client
value:
status: 400
title: Bad Request
error: OAUTH_INVALID_REDIRECT_URI
source:
field: redirect_uri
type: QUERY
detail: Redirect URI is not registered for client.
malformed_redirect_uri:
summary: Redirect URI is not a valid absolute URI
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: redirect_uri
type: QUERY
detail: relative URL without a base
invalid_client_id:
summary: Invalid OAuth client identifier
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: client_id
type: QUERY
detail: must be a valid OAuthClient ID
"401":
description:
Unauthorized — the Cognito bearer token is missing, invalid, or the OAuth client was not found / credentials
are invalid.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
missing_bearer:
summary: Missing or invalid bearer token
value:
status: 401
title: Unauthorized
error: UNAUTHORIZED
client_not_found:
summary: OAuth client not found
value:
status: 401
title: Unauthorized
error: OAUTH_CLIENT_NOT_FOUND
detail: OAuth client not found.
"500":
description: Internal server error.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: INTERNAL_SERVER_ERROR
/api/v1/oauth/token:
post:
summary: OAuth2 token endpoint
description:
"Exchanges a single-use authorization code for an Aura Historia access token (RFC 6749 §4.1.3).
The request body must be `application/x-www-form-urlencoded`. Client authentication is
performed via `client_id` / `client_secret` form fields. PKCE code verification (RFC 7636)
is mandatory: `code_verifier` must produce the `code_challenge` supplied to the authorize
endpoint.
The issued access token is non-expiring by default (same lifetime as tokens created via
`POST /api/v1/me/access-tokens`). Successful responses also include a short-lived
`third_party_exchange_code` that can be redeemed once via
`GET /api/v1/oauth/tokens/by-third-party-code/{thirdPartyCode}`. The exchange code expires
after 60 seconds and is deleted on first use.
"
operationId: oauthToken
tags:
- OAuth
requestBody:
required: true
description: Authorization code exchange payload (form-urlencoded).
content:
application/x-www-form-urlencoded:
schema:
type: object
required:
- grant_type
- code
- redirect_uri
- client_id
- client_secret
- code_verifier
properties:
grant_type:
type: string
enum:
- authorization_code
description: OAuth grant type. Must be `authorization_code`.
example: authorization_code
code:
type: string
description: Single-use authorization code received from the authorize redirect.
example: SplxlOBeZQQYbYS6WxSbIA
redirect_uri:
type: string
format: uri
description: Must exactly match the `redirect_uri` used in the corresponding authorization request.
example: https://client.example/callback
client_id:
type: string
description: Canonical OAuthClient ID.
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_secret:
type: string
description: OAuth client secret.
example: aurahistoria_abcdefghijk_verylongsecretvalue
code_verifier:
type: string
description:
PKCE code verifier. The SHA256 hash of this value must match the `code_challenge` from the
authorization request.
example: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
responses:
"200":
description: Access token issued successfully.
headers:
Cache-Control:
description: Always set to `no-store`.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthTokenResponseData"
example:
access_token: aurahistoria_abcdefghijk_verylongtokenvalue
token_type: BEARER
expires_in: null
scope: product-listings:write
third_party_exchange_code: 01970f22-2bf0-7000-8000-000000000099
"400":
description:
Bad request — a required form field is missing, `client_id` is not a valid OAuthClient ID, `redirect_uri` is
malformed, or an authorization code error occurred (code not found, expired, mismatched client or redirect URI,
or invalid PKCE verifier).
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
missing_grant_type:
summary: Missing grant_type form field
value:
status: 400
title: Bad Request
error: BAD_BODY_VALUE
source:
field: grant_type
type: BODY
detail: Missing form field grant_type
unsupported_grant_type:
summary: Unsupported grant_type
value:
status: 400
title: Bad Request
error: BAD_BODY_VALUE
source:
field: grant_type
type: BODY
detail: Unsupported grant_type 'client_credentials'
code_not_found:
summary: Authorization code not found or already used
value:
status: 400
title: Bad Request
error: OAUTH_AUTHORIZATION_CODE_NOT_FOUND
detail: Authorization code not found.
code_expired:
summary: Authorization code expired
value:
status: 400
title: Bad Request
error: OAUTH_AUTHORIZATION_CODE_EXPIRED
detail: Authorization code expired.
code_client_mismatch:
summary: Authorization code belongs to a different OAuth client
value:
status: 400
title: Bad Request
error: OAUTH_AUTHORIZATION_CODE_CLIENT_MISMATCH
detail: Authorization code does not belong to client.
redirect_uri_mismatch:
summary: Redirect URI does not match the authorization request
value:
status: 400
title: Bad Request
error: OAUTH_AUTHORIZATION_REDIRECT_URI_MISMATCH
detail: Authorization code redirect_uri mismatch.
invalid_code_verifier:
summary: PKCE code verifier does not match
value:
status: 400
title: Bad Request
error: OAUTH_INVALID_CODE_VERIFIER
detail: PKCE code_verifier did not match code_challenge.
malformed_redirect_uri:
summary: Redirect URI is not a valid absolute URI
value:
status: 400
title: Bad Request
error: BAD_BODY_VALUE
source:
field: redirect_uri
type: BODY
detail: relative URL without a base
invalid_client_id:
summary: Invalid OAuth client identifier
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: client_id
type: BODY
detail: must be a valid OAuthClient ID
"401":
description: Unauthorized — invalid OAuth client credentials or unknown OAuth client.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
invalid_client_secret:
summary: Invalid client secret
value:
status: 401
title: Unauthorized
error: INVALID_OAUTH_CLIENT_SECRET
detail: Invalid OAuth client secret.
client_not_found:
summary: OAuth client not found
value:
status: 401
title: Unauthorized
error: OAUTH_CLIENT_NOT_FOUND
detail: OAuth client not found.
"500":
description: Internal server error.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: INTERNAL_SERVER_ERROR
/api/v1/oauth/tokens/by-third-party-code/{thirdPartyCode}:
get:
summary: Exchange OAuth token by third-party code
description:
"Exchanges a one-time `third_party_exchange_code` returned by `POST /api/v1/oauth/token`
for the same Aura Historia access token. No client credentials or bearer token are required.
The exchange code expires after 60 seconds and is deleted whether the exchange succeeds or
fails due to expiry.
"
operationId: oauthTokenByThirdPartyCode
tags:
- OAuth
parameters:
- name: thirdPartyCode
in: path
required: true
description: UUIDv7 one-time exchange code returned by the OAuth token endpoint.
schema:
type: string
format: uuid
example: 01970f22-2bf0-7000-8000-000000000099
responses:
"200":
description: Access token returned successfully for a valid third-party exchange code.
headers:
Cache-Control:
description: Always set to `no-store`.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthTokenResponseData"
example:
access_token: aurahistoria_abcdefghijk_verylongtokenvalue
token_type: BEARER
expires_in: null
scope: product-listings:write
"400":
description:
"Bad request — the path parameter is missing/invalid, or the exchange code was not found
or already expired. The backend currently uses the same
`OAUTH_THIRD_PARTY_EXCHANGE_CODE_NOT_FOUND` error code for both unknown and expired
exchange codes; the `detail` text distinguishes the two cases.
"
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
missing_third_party_code:
summary: Missing third-party exchange code path parameter
value:
status: 400
title: Bad Request
error: BAD_PATH_PARAMETER_VALUE
source:
field: thirdPartyCode
type: PATH
detail: Missing path parameter thirdPartyCode
invalid_third_party_code:
summary: Invalid third-party exchange code
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: thirdPartyCode
type: PATH
detail: Path parameter 'thirdPartyCode' is invalid.
exchange_code_not_found:
summary: Third-party exchange code not found
value:
status: 400
title: Bad Request
error: OAUTH_THIRD_PARTY_EXCHANGE_CODE_NOT_FOUND
detail: Third-party exchange code not found.
exchange_code_expired:
summary: Third-party exchange code expired
value:
status: 400
title: Bad Request
error: OAUTH_THIRD_PARTY_EXCHANGE_CODE_NOT_FOUND
detail: Third-party exchange code expired.
"500":
description: Internal server error.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: INTERNAL_SERVER_ERROR
/api/v1/oauth/revoke:
post:
summary: OAuth2 token revocation endpoint
description:
"Revokes an Aura Historia access token that was issued through the OAuth authorization code
flow (RFC 7009). The request body must be `application/x-www-form-urlencoded`. Client
authentication is performed via `client_id` / `client_secret` form fields.
After revocation the token is immediately inactive and introspection will return
`active: false`. Attempting to revoke an unknown or already-revoked token is not an error.
"
operationId: oauthRevoke
tags:
- OAuth
requestBody:
required: true
description: Token revocation payload (form-urlencoded).
content:
application/x-www-form-urlencoded:
schema:
type: object
required:
- token
- client_id
- client_secret
properties:
token:
type: string
description: The access token to revoke.
example: aurahistoria_abcdefghijk_verylongtokenvalue
client_id:
type: string
description: Canonical OAuthClient ID.
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_secret:
type: string
description: OAuth client secret.
example: aurahistoria_abcdefghijk_verylongsecretvalue
responses:
"200":
description: Token revoked successfully (or token was unknown/already inactive). Empty response body.
headers:
Cache-Control:
description: Always set to `no-store`.
schema:
type: string
example: no-store
"400":
description:
Bad request — a required form field is missing, `client_id` is not a valid OAuthClient ID, or the token value
is invalid.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
missing_token:
summary: Missing token form field
value:
status: 400
title: Bad Request
error: BAD_BODY_VALUE
source:
field: token
type: BODY
detail: Missing form field token
invalid_client_id:
summary: Invalid OAuth client identifier
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: client_id
type: BODY
detail: must be a valid OAuthClient ID
"401":
description: Unauthorized — invalid OAuth client credentials or unknown OAuth client.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
invalid_client_secret:
summary: Invalid client secret
value:
status: 401
title: Unauthorized
error: INVALID_OAUTH_CLIENT_SECRET
detail: Invalid OAuth client secret.
client_not_found:
summary: OAuth client not found
value:
status: 401
title: Unauthorized
error: OAUTH_CLIENT_NOT_FOUND
detail: OAuth client not found.
"500":
description: Internal server error.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: INTERNAL_SERVER_ERROR
/api/v1/oauth/introspect:
post:
summary: OAuth2 token introspection endpoint
description:
"Returns metadata about an Aura Historia access token (RFC 7662). The request body must be
`application/x-www-form-urlencoded`. Client authentication is performed via `client_id` /
`client_secret` form fields.
If the token is unknown, expired, or revoked, `active` is `false` and all other fields are
omitted. Otherwise `active` is `true` and the available token metadata is populated.
"
operationId: oauthIntrospect
tags:
- OAuth
requestBody:
required: true
description: Token introspection payload (form-urlencoded).
content:
application/x-www-form-urlencoded:
schema:
type: object
required:
- token
- client_id
- client_secret
properties:
token:
type: string
description: The access token to introspect.
example: aurahistoria_abcdefghijk_verylongtokenvalue
client_id:
type: string
description: Canonical OAuthClient ID.
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_secret:
type: string
description: OAuth client secret.
example: aurahistoria_abcdefghijk_verylongsecretvalue
responses:
"200":
description: "Introspection result. `active: false` means the token is unknown, expired, or revoked."
headers:
Cache-Control:
description: Always set to `no-store`.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthIntrospectionResponseData"
examples:
active:
summary: Active token
value:
active: true
scope: product-listings:write
client_id: oc_7b0gwc1x49e0mvbt3tfexfqgb5
sub: usr_4hzreqwxgvef69j056bszwwm17
token_type: Bearer
exp: 1780000000
iat: 1748400000
inactive:
summary: Inactive / unknown token
value:
active: false
"400":
description:
Bad request — a required form field is missing, `client_id` is not a valid OAuthClient ID, or the token value
is invalid.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
missing_token:
summary: Missing token form field
value:
status: 400
title: Bad Request
error: BAD_BODY_VALUE
source:
field: token
type: BODY
detail: Missing form field token
invalid_client_id:
summary: Invalid OAuth client identifier
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: client_id
type: BODY
detail: must be a valid OAuthClient ID
"401":
description: Unauthorized — invalid OAuth client credentials or unknown OAuth client.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
invalid_client_secret:
summary: Invalid client secret
value:
status: 401
title: Unauthorized
error: INVALID_OAUTH_CLIENT_SECRET
detail: Invalid OAuth client secret.
client_not_found:
summary: OAuth client not found
value:
status: 401
title: Unauthorized
error: OAUTH_CLIENT_NOT_FOUND
detail: OAuth client not found.
"500":
description: Internal server error.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: INTERNAL_SERVER_ERROR
/api/v1/admin/oauth-clients:
get:
summary: List OAuth client metadata for administration
description: |
Lists registered OAuth client metadata for authenticated administrators.
User and delegated-user principals must have the persisted `ADMIN` business role.
Delegated Aura Historia access-token callers must also have the `access-tokens:read`
capability. The OAuth protocol routes remain under `/api/v1/oauth`.
Results use bounded keyset pagination in fixed `created` ascending, then OAuthClient ID ascending order. Page sizes are clamped to 1–100, with a default of 21. The
`searchAfter` value is a JSON-encoded `[created RFC3339 timestamp, OAuthClient ID]`
cursor; it is omitted on the terminal page and must be sent with the same filters.
`clientId` is an exact OAuthClient ID filter. `name` is a case-insensitive substring filter.
The response contains no plaintext client secret, secret hash, or masked secret value.
Every success and error response uses `Cache-Control: no-store`.
operationId: adminListOAuthClients
tags:
- OAuth
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: clientId
in: query
required: false
description: Optional exact OAuthClient ID filter.
schema:
type: string
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
- name: name
in: query
required: false
description: Optional case-insensitive substring filter for the OAuth client display name.
schema:
type: string
example: dashboard
- name: searchAfter
in: query
required: false
description: JSON-encoded `[created RFC3339 timestamp, OAuthClient ID]` cursor returned by the previous page.
schema:
type: string
example: '["2026-09-04T12:00:00Z","oc_7b0gwc1x49e0mvbt3tfexfqgb5"]'
- name: size
in: query
required: false
description: Number of OAuth client summaries requested per page. The server clamps values to 1–100.
schema:
type: integer
format: int64
minimum: 1
maximum: 100
default: 21
example: 21
responses:
"200":
description: OAuth client summaries returned successfully.
headers:
Cache-Control:
description: Responses are never stored because administrator OAuth data is returned.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthClientAdminCollectionData"
example:
items:
- client_id: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_name: Dashboard integration
tos_uri: https://client.example/tos
policy_uri: https://client.example/policy
client_uri: https://client.example
logo_uri: https://client.example/logo.png
redirect_uris:
- https://client.example/callback
scope:
- access-tokens:read
client_id_issued_at: 1748539200
size: 21
searchAfter:
- "2026-09-04T12:00:00Z"
- oc_7b0gwc1x49e0mvbt3tfexfqgb5
"400":
description: Bad request — an OAuth client filter, page size, or cursor is invalid.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: searchAfter
type: QUERY
"401":
description: Unauthorized — invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden — the caller is not an administrator or a delegated caller lacks `access-tokens:read`.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: OAuth client administration requires the ADMIN role; delegated callers also require access-tokens:read.
"500":
description: Internal authentication, authorization, or OAuth client read failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: OAUTH_INTERNAL_ERROR
"503":
description: Temporary authentication, authorization, or OAuth client read failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: OAUTH_TEMPORARILY_UNAVAILABLE
post:
summary: Create OAuth client metadata for administration
description: |
Creates a new OAuth client metadata record for an authenticated administrator.
User and delegated-user principals must have the persisted `ADMIN` business role.
Delegated Aura Historia access-token callers must also have the `access-tokens:write`
capability. The plaintext `client_secret` is returned only in this create response and
is never logged or returned by later reads.
Redirect URIs must be non-empty HTTPS URLs without fragments. Requested scopes must be
supported OAuth scopes.
operationId: adminCreateOAuthClient
tags:
- OAuth
security:
- BearerAuth: []
- AccessTokenAuth: []
requestBody:
required: true
description: OAuth client metadata creation payload.
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthClientMetadataRequestData"
example:
client_name: Acceptance OAuth client
tos_uri: https://client.example/tos
policy_uri: https://client.example/policy
client_uri: https://client.example
logo_uri: https://client.example/logo.png
redirect_uris:
- https://client.example/callback
scope:
- product-listings:write
responses:
"201":
description: OAuth client metadata created successfully.
headers:
Location:
description: URL of the created admin OAuth client detail resource.
schema:
type: string
format: uri
example: /api/v1/admin/oauth-clients/oc_7b0gwc1x49e0mvbt3tfexfqgb5
Cache-Control:
description: Always set to `no-store` because the response contains the raw secret.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthClientMetadataResponseData"
example:
client_id: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_secret: aurahistoria_oauth_client_secret_abcdefghijk_abcdefghijklmnopqrstuvwxyz1234567
client_name: Acceptance OAuth client
tos_uri: https://client.example/tos
policy_uri: https://client.example/policy
client_uri: https://client.example
logo_uri: https://client.example/logo.png
redirect_uris:
- https://client.example/callback
scope:
- product-listings:write
client_id_issued_at: 1748539200
"400":
description: Bad request — missing, empty, malformed JSON body, invalid redirect URI, or unsupported scope.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
missing_body:
summary: Missing request body
value:
status: 400
title: Bad Request
error: BAD_BODY_VALUE
detail: Body cannot be empty
empty_redirect_uris:
summary: Redirect URIs are required
value:
status: 400
title: Bad Request
error: OAUTH_INVALID_CLIENT_METADATA
detail: "OAuth client metadata is invalid: OAuth client must have at least one redirect URI"
insecure_redirect_uri:
summary: Redirect URI must use HTTPS
value:
status: 400
title: Bad Request
error: OAUTH_INVALID_CLIENT_METADATA
detail: "OAuth client metadata is invalid: OAuth redirect URI must use HTTPS: http://client.example/callback"
"401":
description: Unauthorized — invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden — the caller is not an administrator or a delegated caller lacks `access-tokens:write`.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: OAuth client creation requires the ADMIN role; delegated callers also require access-tokens:write.
"500":
description: Internal authentication or OAuth client creation failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: OAUTH_INTERNAL_ERROR
"503":
description: Temporary authentication, authorization, or OAuth client persistence failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: OAUTH_TEMPORARILY_UNAVAILABLE
/api/v1/admin/oauth-clients/{clientId}:
get:
summary: Get OAuth client metadata for administration
description: |
Retrieves one OAuth client metadata record for an authenticated administrator.
User and delegated-user principals must have the persisted `ADMIN` business role.
Delegated Aura Historia access-token callers must also have the `access-tokens:read`
capability. The response contains client metadata, redirect URIs, and scopes, but never
a plaintext client secret, secret hash, or masked secret value. Every success and error
response uses `Cache-Control: no-store`.
operationId: adminGetOAuthClient
tags:
- OAuth
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: clientId
in: path
required: true
description: Canonical OAuthClient ID.
schema:
type: string
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
responses:
"200":
description: OAuth client metadata retrieved successfully.
headers:
Cache-Control:
description: Responses are never stored because administrator OAuth data is returned.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthClientAdminData"
example:
client_id: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_name: Acceptance OAuth client
tos_uri: https://client.example/tos
policy_uri: https://client.example/policy
client_uri: https://client.example
logo_uri: https://client.example/logo.png
redirect_uris:
- https://client.example/callback
scope:
- product-listings:write
client_id_issued_at: 1748539200
"400":
description: Bad request — the OAuth client path parameter is not a valid OAuthClient ID.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: clientId
type: PATH
detail: must be a valid OAuthClient ID
"401":
description: Unauthorized — invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden — the caller is not an administrator or a delegated caller lacks `access-tokens:read`.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: OAuth client administration requires the ADMIN role; delegated callers also require access-tokens:read.
"404":
description: OAuth client was not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 404
title: Not Found
error: OAUTH_CLIENT_NOT_FOUND
detail: OAuth client not found.
"500":
description: Internal authentication, authorization, or OAuth client read failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: OAUTH_INTERNAL_ERROR
"503":
description: Temporary authentication, authorization, or OAuth client read failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: OAUTH_TEMPORARILY_UNAVAILABLE
patch:
summary: Update OAuth client metadata for administration
description: |
Updates one OAuth client metadata record for an authenticated administrator.
Omitted properties leave existing values unchanged; every explicit `null` is invalid
because OAuth metadata is non-nullable; and `{}` is a valid no-op.
User and delegated-user principals must have the persisted `ADMIN` business role.
Delegated Aura Historia access-token callers must also have the `access-tokens:write`
capability. Redirect URIs remain non-empty HTTPS URLs without fragments, and requested
scopes must be supported OAuth scopes.
The response is secret-free. This operation never exposes or rotates the client secret.
Every success and error response uses `Cache-Control: no-store`.
operationId: adminPatchOAuthClient
tags:
- OAuth
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: clientId
in: path
required: true
description: Canonical OAuthClient ID.
schema:
type: string
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
requestBody:
required: true
description: Partial OAuth client metadata update payload.
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthClientMetadataPatchData"
example:
client_name: Updated acceptance OAuth client
tos_uri: https://client.example/updated-tos
policy_uri: https://client.example/updated-policy
client_uri: https://updated-client.example
logo_uri: https://updated-client.example/logo.png
redirect_uris:
- https://client.example/updated
scope:
- access-tokens:read
responses:
"200":
description: OAuth client metadata updated successfully without exposing a secret.
headers:
Cache-Control:
description: Always set to `no-store`.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/OAuthClientAdminData"
example:
client_id: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_name: Updated acceptance OAuth client
tos_uri: https://client.example/updated-tos
policy_uri: https://client.example/updated-policy
client_uri: https://updated-client.example
logo_uri: https://updated-client.example/logo.png
redirect_uris:
- https://client.example/updated
scope:
- access-tokens:read
client_id_issued_at: 1748539200
"400":
description: Bad request — invalid client ID, empty/malformed body, null patch member, invalid redirect URI, or unsupported scope.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
invalid_client_id:
summary: Invalid OAuth client identifier
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: clientId
type: PATH
detail: must be a valid OAuthClient ID
insecure_redirect_uri:
summary: Redirect URI must use HTTPS
value:
status: 400
title: Bad Request
error: OAUTH_INVALID_CLIENT_METADATA
detail: "OAuth client metadata is invalid: OAuth redirect URI must use HTTPS: http://client.example/updated"
"401":
description: Unauthorized — invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden — the caller is not an administrator or a delegated caller lacks `access-tokens:write`.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: OAuth client administration requires the ADMIN role; delegated callers also require access-tokens:write.
"404":
description: OAuth client was not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 404
title: Not Found
error: OAUTH_CLIENT_NOT_FOUND
"500":
description: Internal authentication, authorization, or OAuth client update failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: OAUTH_INTERNAL_ERROR
"503":
description: Temporary authentication, authorization, or OAuth client update failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: OAUTH_TEMPORARILY_UNAVAILABLE
delete:
summary: Delete OAuth client metadata for administration
description: |
Deletes one OAuth client metadata record for an authenticated administrator.
User and delegated-user principals must have the persisted `ADMIN` business role.
Delegated Aura Historia access-token callers must also have the `access-tokens:write`
capability. Deletion atomically invalidates pending authorization codes, OAuth-issued
Aura access tokens, and their one-time third-party exchange codes. The OAuth protocol
routes remain under `/api/v1/oauth`; this administrative mutation is not a protocol route.
operationId: adminDeleteOAuthClient
tags:
- OAuth
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: clientId
in: path
required: true
description: Canonical OAuthClient ID.
schema:
type: string
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
responses:
"204":
description: OAuth client and all client-issued credentials were deleted successfully.
headers:
Cache-Control:
description: Responses are never stored.
schema:
type: string
example: no-store
"400":
description: Bad request — the OAuth client path parameter is not a valid OAuthClient ID.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: clientId
type: PATH
detail: must be a valid OAuthClient ID
"401":
description: Unauthorized — invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden — the caller is not an administrator or a delegated caller lacks `access-tokens:write`.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: OAuth client administration requires the ADMIN role; delegated callers also require access-tokens:write.
"404":
description: OAuth client was not found, including repeated deletion.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 404
title: Not Found
error: OAUTH_CLIENT_NOT_FOUND
"500":
description: Internal authentication, authorization, or OAuth client deletion failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: OAUTH_INTERNAL_ERROR
"503":
description: Temporary authentication, authorization, or OAuth client deletion failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: OAUTH_TEMPORARILY_UNAVAILABLE
/api/v1/listing-sources:
get:
summary: Search public ListingSources
description: Anonymous, literal partial-name search and browse of every persisted ListingSource. Optional valid credentials never widen the public representation; invalid supplied credentials are rejected. Query values are NFC/Unicode-whitespace canonicalized. One scalar and punctuation-only input return a terminal empty collection.
operationId: searchPublicListingSources
tags:
- ListingSources
security:
- {}
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: query
in: query
schema:
type: string
maxLength: 256
description: Optional contiguous literal text. Only `query`, `size`, and `searchAfter` are accepted once; unknown or repeated parameters return 400.
- name: size
in: query
schema:
type: integer
minimum: 1
maximum: 50
default: 21
- name: searchAfter
in: query
schema:
type: string
description: Opaque URL-safe base64 continuation from this endpoint. Omit on the first page and restart after a query or size change.
responses:
"200":
description: Anonymous successful 200 responses without Authorization use `public, max-age=0, s-maxage=300, stale-if-error=0`; any request with Authorization and all errors use `private, no-store`.
headers:
Cache-Control:
schema: { type: string }
example: public, max-age=0, s-maxage=300, stale-if-error=0
content:
application/json:
schema:
$ref: "#/components/schemas/PublicListingSourceSearchCollectionData"
"400":
description: Invalid query parameter or continuation. Cache-Control is no-store.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ApiError" }
"401":
description: Invalid supplied credential. Cache-Control is no-store.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ApiError" }
"500":
description: Invalid persisted public read model. Cache-Control is no-store.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ApiError" }
"503":
description: Temporary public-read failure. Cache-Control is no-store.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ApiError" }
/api/v1/listing-sources/by-slug/{listingSourceSlugId}:
get:
summary: Get a public ListingSource by immutable slug
description: Anonymous exact immutable-slug lookup. This route accepts no query parameters. Optional valid credentials never widen the public representation; invalid supplied credentials are rejected.
operationId: getPublicListingSourceBySlug
tags:
- ListingSources
security:
- {}
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: listingSourceSlugId
in: path
required: true
schema:
type: string
description: Exact persisted immutable ListingSource slug.
responses:
"200":
description: Anonymous successful 200 responses without Authorization use `public, max-age=0, s-maxage=300, stale-if-error=0`; any request with Authorization and all errors use `private, no-store`.
headers:
Cache-Control:
schema: { type: string }
example: public, max-age=0, s-maxage=300, stale-if-error=0
content:
application/json:
schema:
$ref: "#/components/schemas/PublicListingSourceData"
"400":
description: Invalid slug or nonempty query string. Cache-Control is no-store.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ApiError" }
"401":
description: Invalid supplied credential. Cache-Control is no-store.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ApiError" }
"404":
description: LISTING_SOURCE_NOT_FOUND. Cache-Control is no-store.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ApiError" }
"500":
description: Invalid persisted public read model. Cache-Control is no-store.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ApiError" }
"503":
description: Temporary public-read failure. Cache-Control is no-store.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/ApiError" }
/api/v1/me/listing-sources:
get:
summary: List caller-administered ListingSources
description: Delegated Aura access tokens require `listing-sources:read`; missing scope returns `403 FORBIDDEN`.
operationId: getMyListingSources
tags:
- ListingSources
responses:
"200":
description: Success
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/AdministeredListingSourceData"
"401":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"500":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"503":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
security:
- BearerAuth: []
- AccessTokenAuth: []
/api/v1/me/partnership-applications:
get:
summary: List caller PartnershipApplications
description: Delegated Aura access tokens require `partnership-applications:read`; missing scope returns `403 FORBIDDEN`.
operationId: getMyPartnershipApplications
tags:
- PartnershipApplications
responses:
"200":
description: Success
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/OwnPartnershipApplicationData"
"401":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"500":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"503":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
security:
- BearerAuth: []
- AccessTokenAuth: []
post:
summary: Submit a PartnershipApplication
description: Delegated Aura access tokens require `partnership-applications:write`; missing scope returns `403 FORBIDDEN`.
operationId: postPartnershipApplication
tags:
- PartnershipApplications
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/SubmitPartnershipApplicationData"
responses:
"201":
description: PartnershipApplication submitted
content:
application/json:
schema:
$ref: "#/components/schemas/OwnPartnershipApplicationData"
"400":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"401":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"404":
description: "PARTNERSHIP_APPLICATION_LISTING_SOURCE_NOT_FOUND when an existing ListingSource proposal references a missing source"
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"500":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"503":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
security:
- BearerAuth: []
- AccessTokenAuth: []
/api/v1/me/partnership-applications/{partnershipApplicationId}:
get:
summary: Get a caller PartnershipApplication
description: Delegated Aura access tokens require `partnership-applications:read`; missing scope returns `403 FORBIDDEN`.
operationId: getOwnPartnershipApplication
tags:
- PartnershipApplications
parameters:
- name: partnershipApplicationId
in: path
required: true
schema:
type: string
responses:
"200":
description: Success
content:
application/json:
schema:
$ref: "#/components/schemas/OwnPartnershipApplicationData"
"400":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"401":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"404":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"500":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"503":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
security:
- BearerAuth: []
- AccessTokenAuth: []
delete:
summary: Withdraw a PartnershipApplication
description: Delegated Aura access tokens require `partnership-applications:write`; missing scope returns `403 FORBIDDEN`.
operationId: deleteOwnPartnershipApplication
tags:
- PartnershipApplications
parameters:
- name: partnershipApplicationId
in: path
required: true
schema:
type: string
responses:
"204":
description: PartnershipApplication withdrawn
"400":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"401":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"404":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"409":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"500":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
"503":
description: Problem response
content:
application/json:
schema:
$ref: "#/components/schemas/ApiError"
security:
- BearerAuth: []
- AccessTokenAuth: []
/api/v1/admin/overview:
get:
summary: Get the administrator operational overview
description: |
Delegated Aura access tokens require `admin-overview:read`; missing scope returns `403 FORBIDDEN`.
Returns a bounded landing-page summary for authenticated administrators. `schemaVersion` is
required so clients can select a compatible response decoder. Every counter is read from
authoritative PostgreSQL by one aggregate statement; OpenSearch and other rebuildable
projections are not used.
`listingSources.methodAssignments` counts source-method assignments, not distinct sources,
so its values may sum to more than `listingSources.total`. ProductListing availability
counts include only `ACTIVE` listings; `activeWithoutAvailability` identifies active rows
without a current source availability assertion. Responses contain no PII, secrets, or
embedded collections and always use `Cache-Control: no-store`.
operationId: getAdminOverview
tags:
- Administration
security:
- BearerAuth: []
- AccessTokenAuth: []
responses:
"200":
description: Authoritative operational counters returned successfully.
headers:
Cache-Control:
description: Administrator overview responses are never stored.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/AdminOverviewData"
"401":
description: Missing or invalid bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: The caller does not have the persisted ADMIN role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
"500":
description: An invalid authoritative read model or internal overview failure occurred.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: ADMIN_OVERVIEW_INTERNAL_ERROR
"503":
description: PostgreSQL or persisted administrator authorization is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: ADMIN_OVERVIEW_TEMPORARILY_UNAVAILABLE
/api/v1/admin/partnerships:
get:
summary: List Partnerships for administration
description: |
Delegated Aura access tokens require `partnerships:read`; missing scope returns `403 FORBIDDEN`.
Lists active Partnerships for authenticated administrators.
Results use bounded keyset cursor pagination in fixed `created` descending, then
Partnership ID descending order. Page sizes are clamped to 1–100, with a default
of 21. The returned `searchAfter` value is a JSON-encoded
`[created RFC3339 timestamp, Partnership ID]` cursor; it is omitted on the terminal
page and should be sent with the same filters for the next page.
Optional `partyId`, `memberUserId`, and `listingSourceId` filters are exact object-ID
matches and are combined when supplied. Each result is a safe summary containing
the Partnership ID, Party ID/immutable slug/name, member count, ListingSource-grant
count, and creation/update timestamps. Member identities, grant identities, Party
contact data, persistence versions, provider credentials, webhook secrets, and
crawler-local configuration are never returned. Responses always use
`Cache-Control: no-store`.
operationId: adminSearchPartnerships
tags:
- Partnerships
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: partyId
in: query
required: false
description: Optional exact Party ID filter.
schema:
type: string
example: pty_4k4snxc3pkecc9yw66heemzyp0
- name: memberUserId
in: query
required: false
description: Optional exact member User ID filter.
schema:
type: string
example: usr_5kgk59yyskf6fb0gyc9fxn5gwk
- name: listingSourceId
in: query
required: false
description: Optional exact ListingSource grant ID filter.
schema:
type: string
example: ls_0geqhfpd80f6ga8zv98d2vcd1v
- name: searchAfter
in: query
required: false
description: JSON-encoded `[created RFC3339 timestamp, Partnership ID]` cursor returned by the previous page.
schema:
type: string
example: '["2026-09-04T12:00:00Z","psh_3q65ndcw7wfxqswjtrv1kfhwd1"]'
- name: size
in: query
required: false
description: Number of Partnership summaries requested per page. The server clamps values to 1–100.
schema:
type: integer
format: int64
minimum: 1
maximum: 100
default: 21
example: 21
responses:
"200":
description: Partnership summaries returned successfully.
headers:
Cache-Control:
description: Responses are never stored because this is an administrator-only read.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/AdminPartnershipCollectionData"
example:
items:
- partnershipId: psh_3q65ndcw7wfxqswjtrv1kfhwd1
party:
partyId: pty_4k4snxc3pkecc9yw66heemzyp0
partySlugId: safe-party
name: Safe Party
memberCount: 2
listingSourceGrantCount: 3
created: "2026-09-04T12:00:00Z"
updated: "2026-09-04T13:00:00Z"
size: 21
searchAfter:
- "2026-09-04T12:00:00Z"
- psh_3q65ndcw7wfxqswjtrv1kfhwd1
"400":
description: Bad request - invalid Partnership query parameter.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden - this endpoint requires the `ADMIN` role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: Operation is not permitted.
"500":
description: Internal authentication or Partnership search failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: PARTNERSHIP_INTERNAL_ERROR
"503":
description: Authentication, admin authorization, or Partnership search is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: PARTNERSHIP_TEMPORARILY_UNAVAILABLE
/api/v1/admin/partnerships/{partnershipId}:
get:
summary: Get a Partnership for administration
description: |
Delegated Aura access tokens require `partnerships:read`; missing scope returns `403 FORBIDDEN`.
Returns one established Partnership for an authenticated administrator.
The response includes the Partnership identity, its Party reference, current member user
references, and current ListingSource grant references. Member and grant references are
ordered by ID and each array is bounded to at most 100 entries. `memberCount` and
`listingSourceGrantCount` are complete counts, including references beyond the bounded arrays.
Missing Partnerships return `PARTNERSHIP_NOT_FOUND`. All success and error responses use
`Cache-Control: no-store` because member user identifiers are returned.
operationId: adminGetPartnership
tags:
- Partnerships
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: partnershipId
in: path
required: true
description: Stable Partnership ID.
schema:
type: string
example: psh_3q65ndcw7wfxqswjtrv1kfhwd1
responses:
"200":
description: Partnership details returned successfully.
headers:
Cache-Control:
description: Responses are never stored because member user identifiers are returned.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/AdminPartnershipDetailsData"
example:
partnershipId: psh_3q65ndcw7wfxqswjtrv1kfhwd1
party:
partyId: pty_4k4snxc3pkecc9yw66heemzyp0
partySlugId: safe-party
name: Safe Party
memberUserIds:
- usr_5kgk59yyskf6fb0gyc9fxn5gwk
- usr_7hqr3y7dfze74sfm30pg9t3nvp
listingSourceIds:
- ls_1jy6kc0gpnecws80wddqee2rtq
- ls_25b9fry680eh9txe84nex6vk2a
memberCount: 2
listingSourceGrantCount: 2
created: "2026-09-04T12:00:00Z"
updated: "2026-09-04T13:00:00Z"
"400":
description: Bad request - invalid Partnership ID.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: partnershipId
type: PATH
detail: must be a valid Partnership ID
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden - this endpoint requires the `ADMIN` role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
"404":
description: Partnership not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 404
title: Not Found
error: PARTNERSHIP_NOT_FOUND
"500":
description: Internal authentication or Partnership detail failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: PARTNERSHIP_INTERNAL_ERROR
"503":
description: Authentication, admin authorization, or Partnership detail is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: PARTNERSHIP_TEMPORARILY_UNAVAILABLE
delete:
summary: Dissolve a Partnership
description: |
Delegated Aura access tokens require `partnerships:write`; missing scope returns `403 FORBIDDEN`.
Semantically deletes a Partnership for an authenticated administrator. The Partnership row
remains as a `DISSOLVED` historical reference for approved PartnershipApplications, while
all current membership and ListingSource-grant rows are removed in the same PostgreSQL
transaction. ListingSources, Parties, users, ProductListings, and applications are not
deleted. Repeating a successful dissolution is an idempotent `204` no-op. No user can
retain Partnership authorization after the transaction commits. All responses use
`Cache-Control: no-store`.
operationId: adminDissolvePartnership
tags:
- Partnerships
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: partnershipId
in: path
required: true
description: Stable Partnership ID.
schema:
type: string
responses:
"204":
description: Partnership dissolved, or already dissolved.
headers:
Cache-Control:
description: Responses are never stored.
schema:
type: string
example: no-store
"400":
description: Bad request - invalid Partnership ID (`INVALID_OBJECT_ID`).
"401":
description: Unauthorized - invalid or missing bearer credentials (`INVALID_CREDENTIALS`).
"403":
description: Forbidden - this endpoint requires the `ADMIN` role (`FORBIDDEN`).
"404":
description: Partnership not found.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 404
title: Not Found
error: PARTNERSHIP_NOT_FOUND
"409":
description: Partnership was changed concurrently.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 409
title: Conflict
error: CONFLICT
"500":
description: Internal Partnership dissolution failure (`PARTNERSHIP_INTERNAL_ERROR`).
"503":
description: Authentication, admin authorization, or Partnership dissolution is temporarily unavailable.
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: PARTNERSHIP_TEMPORARILY_UNAVAILABLE
/api/v1/admin/partnerships/{partnershipId}/listing-source-grants/{listingSourceId}:
put:
summary: Grant a ListingSource to a Partnership
description: |
Delegated Aura access tokens require `partnerships:write`; missing scope returns `403 FORBIDDEN`.
Idempotently grants an existing ListingSource to an existing Partnership for an
authenticated administrator. The Partnership and ListingSource must belong to the same
Party; a mismatched Party is rejected with `409 CONFLICT`. An existing grant is a
successful no-op. The operation is committed in one PostgreSQL transaction and returns no
response body. All success and error responses use `Cache-Control: no-store`.
operationId: adminGrantPartnershipListingSource
tags:
- Partnerships
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: partnershipId
in: path
required: true
description: Stable Partnership ID.
schema:
type: string
example: psh_3q65ndcw7wfxqswjtrv1kfhwd1
- name: listingSourceId
in: path
required: true
description: Existing ListingSource ID to grant to the Partnership.
schema:
type: string
example: ls_1jy6kc0gpnecws80wddqee2rtq
responses:
"204":
description: ListingSource grant created, or ListingSource grant already existed.
headers:
Cache-Control:
description: Responses are never stored because this is an administrator-only mutation.
schema:
type: string
example: no-store
"400":
description: Bad request - invalid Partnership or ListingSource ID.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
invalidPartnershipId:
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: partnershipId
type: PATH
detail: must be a valid Partnership ID
invalidListingSourceId:
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: listingSourceId
type: PATH
detail: must be a valid ListingSource ID
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden - this endpoint requires the `ADMIN` role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: Operation is not permitted.
"404":
description: Partnership or ListingSource not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
partnershipNotFound:
value:
status: 404
title: Not Found
error: PARTNERSHIP_NOT_FOUND
detail: Partnership was not found.
listingSourceNotFound:
value:
status: 404
title: Not Found
error: LISTING_SOURCE_NOT_FOUND
detail: Listing source was not found.
"409":
description: Partnership and ListingSource belong to different Parties.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 409
title: Conflict
error: CONFLICT
detail: Partnership and ListingSource belong to different Parties.
"500":
description: Internal Partnership ListingSource grant failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: PARTNERSHIP_INTERNAL_ERROR
"503":
description: Authentication, admin authorization, transaction, or Partnership ListingSource grant persistence is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: PARTNERSHIP_TEMPORARILY_UNAVAILABLE
delete:
summary: Revoke a ListingSource from a Partnership
description: |
Delegated Aura access tokens require `partnerships:write`; missing scope returns `403 FORBIDDEN`.
Idempotently removes an existing ListingSource grant from an existing Partnership for an
authenticated administrator. Only the targeted Partnership/ListingSource join row is
removed; the Partnership, ListingSource, members, and historical PartnershipApplications
are preserved. An absent grant is a successful no-op. The operation is committed in one
PostgreSQL transaction and returns no response body. All success and error responses use
`Cache-Control: no-store`.
operationId: adminRevokePartnershipListingSource
tags:
- Partnerships
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: partnershipId
in: path
required: true
description: Stable Partnership ID.
schema:
type: string
example: psh_3q65ndcw7wfxqswjtrv1kfhwd1
- name: listingSourceId
in: path
required: true
description: Existing ListingSource ID whose Partnership grant should be revoked.
schema:
type: string
example: ls_1jy6kc0gpnecws80wddqee2rtq
responses:
"204":
description: ListingSource grant removed, or ListingSource grant was already absent.
headers:
Cache-Control:
description: Responses are never stored because this is an administrator-only mutation.
schema:
type: string
example: no-store
"400":
description: Bad request - invalid Partnership or ListingSource ID.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
invalidPartnershipId:
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: partnershipId
type: PATH
detail: must be a valid Partnership ID
invalidListingSourceId:
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: listingSourceId
type: PATH
detail: must be a valid ListingSource ID
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden - this endpoint requires the `ADMIN` role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: Operation is not permitted.
"404":
description: Partnership or ListingSource not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
partnershipNotFound:
value:
status: 404
title: Not Found
error: PARTNERSHIP_NOT_FOUND
detail: Partnership was not found.
listingSourceNotFound:
value:
status: 404
title: Not Found
error: LISTING_SOURCE_NOT_FOUND
detail: Listing source was not found.
"500":
description: Internal Partnership ListingSource grant revocation failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: PARTNERSHIP_INTERNAL_ERROR
"503":
description: Authentication, admin authorization, transaction, or Partnership ListingSource grant revocation persistence is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: PARTNERSHIP_TEMPORARILY_UNAVAILABLE
/api/v1/admin/partnerships/{partnershipId}/members/{userId}:
put:
summary: Grant a user membership in a Partnership
description: |
Delegated Aura access tokens require `partnerships:write`; missing scope returns `403 FORBIDDEN`.
Idempotently grants the target user membership in the specified Partnership for an
authenticated administrator. The target user and Partnership must already exist. An
existing membership is a successful no-op. The operation is committed in one PostgreSQL
transaction and returns no response body. All success and error responses use
`Cache-Control: no-store`.
operationId: adminGrantPartnershipMembership
tags:
- Partnerships
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: partnershipId
in: path
required: true
description: Stable Partnership ID.
schema:
type: string
example: psh_3q65ndcw7wfxqswjtrv1kfhwd1
- name: userId
in: path
required: true
description: Existing User ID to add as a Partnership member.
schema:
type: string
example: usr_5kgk59yyskf6fb0gyc9fxn5gwk
responses:
"204":
description: Membership granted, or membership already existed.
headers:
Cache-Control:
description: Responses are never stored because this is an administrator-only mutation.
schema:
type: string
example: no-store
"400":
description: Bad request - invalid Partnership or User ID.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
invalidPartnershipId:
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: partnershipId
type: PATH
detail: must be a valid Partnership ID
invalidUserId:
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: userId
type: PATH
detail: must be a valid User ID
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden - this endpoint requires the `ADMIN` role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: Operation is not permitted.
"404":
description: Partnership or target user not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
partnershipNotFound:
value:
status: 404
title: Not Found
error: PARTNERSHIP_NOT_FOUND
detail: Partnership was not found.
userNotFound:
value:
status: 404
title: Not Found
error: USER_NOT_FOUND
detail: User was not found.
"500":
description: Internal Partnership membership failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: PARTNERSHIP_INTERNAL_ERROR
"503":
description: Authentication, admin authorization, transaction, or Partnership membership persistence is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: PARTNERSHIP_TEMPORARILY_UNAVAILABLE
delete:
summary: Revoke a user membership in a Partnership
description: |
Delegated Aura access tokens require `partnerships:write`; missing scope returns `403 FORBIDDEN`.
Idempotently removes the target user membership from the specified Partnership for an
authenticated administrator. The target user and Partnership must already exist. A missing
membership is a successful no-op. Only the membership row is removed; the user, Partnership,
ListingSource, and historical PartnershipApplication records are preserved. The operation is
committed in one PostgreSQL transaction and returns no response body. All success and error
responses use `Cache-Control: no-store`.
operationId: adminRevokePartnershipMembership
tags:
- Partnerships
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: partnershipId
in: path
required: true
description: Stable Partnership ID.
schema:
type: string
example: psh_3q65ndcw7wfxqswjtrv1kfhwd1
- name: userId
in: path
required: true
description: Existing User ID to remove from the Partnership.
schema:
type: string
example: usr_5kgk59yyskf6fb0gyc9fxn5gwk
responses:
"204":
description: Membership removed, or membership was already absent.
headers:
Cache-Control:
description: Responses are never stored because this is an administrator-only mutation.
schema:
type: string
example: no-store
"400":
description: Bad request - invalid Partnership or User ID.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
invalidPartnershipId:
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: partnershipId
type: PATH
detail: must be a valid Partnership ID
invalidUserId:
value:
status: 400
title: Bad Request
error: INVALID_OBJECT_ID
source:
field: userId
type: PATH
detail: must be a valid User ID
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 401
title: Unauthorized
error: INVALID_CREDENTIALS
"403":
description: Forbidden - this endpoint requires the `ADMIN` role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 403
title: Forbidden
error: FORBIDDEN
detail: Operation is not permitted.
"404":
description: Partnership or target user not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
partnershipNotFound:
value:
status: 404
title: Not Found
error: PARTNERSHIP_NOT_FOUND
detail: Partnership was not found.
userNotFound:
value:
status: 404
title: Not Found
error: USER_NOT_FOUND
detail: User was not found.
"500":
description: Internal Partnership membership failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 500
title: Internal Server Error
error: PARTNERSHIP_INTERNAL_ERROR
"503":
description: Authentication, admin authorization, transaction, or Partnership membership persistence is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
example:
status: 503
title: Service Unavailable
error: PARTNERSHIP_TEMPORARILY_UNAVAILABLE
/api/v1/admin/partnership-applications:
get:
summary: Search PartnershipApplications for administration
description: |
Delegated Aura access tokens require `partnership-applications:read`; missing scope returns `403 FORBIDDEN`.
Searches PartnershipApplications for authenticated administrators.
`state` and `proposalType` accept repeated exact canonical values. `applicantUserId`
restricts the applicant. `listingSourceId` matches the approved ListingSource or an
existing ListingSource proposed by the application. `created` and `updated` accept
inclusive RFC3339 ranges using `min` and `max` query members.
Results use deterministic keyset cursor pagination. The default sort is `created` descending;
override it by providing both `sort` and `order`. Valid sort fields are `created` and `updated`;
PartnershipApplication ID is always the final deterministic tie-breaker. Page sizes are clamped
to 1–100, with a default of 21. The returned JSON `[timestamp, PartnershipApplication ID]` `searchAfter`
cursor is omitted on the terminal page and must be sent with the same filters and sort.
Results contain review-queue summary data only and never expose persistence version values.
Responses always use `Cache-Control: no-store`.
operationId: adminSearchPartnershipApplications
tags:
- PartnershipApplications
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: state
in: query
required: false
description: Repeated exact application state filters. Matching any supplied state is allowed.
style: form
explode: true
schema:
type: array
items:
$ref: "#/components/schemas/PartnershipApplicationStateData"
example:
- SUBMITTED
- IN_REVIEW
- name: applicantUserId
in: query
required: false
description: Optional applicant User ID filter.
schema:
type: string
example: usr_5pvhvpxyhve6ts31n9x8c2y513
- name: proposalType
in: query
required: false
description: Repeated exact proposal type filters. Matching any supplied type is allowed.
style: form
explode: true
schema:
type: array
items:
$ref: "#/components/schemas/PartnershipProposalTypeData"
example:
- EXISTING_LISTING_SOURCE
- name: listingSourceId
in: query
required: false
description: Optional approved or existing-proposal ListingSource ID filter.
schema:
type: string
example: ls_7h03ebvas3fhj9qb5pr5s22029
- name: "created[min]"
in: query
required: false
description: Optional inclusive lower bound for application creation time (RFC3339).
schema:
type: string
format: date-time
example: "2026-01-01T00:00:00Z"
- name: "created[max]"
in: query
required: false
description: Optional inclusive upper bound for application creation time (RFC3339).
schema:
type: string
format: date-time
example: "2026-12-31T23:59:59Z"
- name: "updated[min]"
in: query
required: false
description: Optional inclusive lower bound for application update time (RFC3339).
schema:
type: string
format: date-time
example: "2026-01-01T00:00:00Z"
- name: "updated[max]"
in: query
required: false
description: Optional inclusive upper bound for application update time (RFC3339).
schema:
type: string
format: date-time
example: "2026-12-31T23:59:59Z"
- name: sort
in: query
required: false
description: Sort field. Valid values are `created` and `updated`. The default is `created` descending.
schema:
type: string
enum:
- created
- updated
example: created
- name: order
in: query
required: false
description: Sort direction for `sort`. Provide both `sort` and `order` to override the default.
schema:
type: string
enum:
- asc
- desc
example: desc
- name: searchAfter
in: query
required: false
description: Opaque JSON-encoded `[timestamp, PartnershipApplication ID]` cursor returned by the previous page.
schema:
type: string
example: '["2026-09-04T12:00:00Z","pa_0ckcsff4zne3qr4dsrvqk7fckd"]'
- name: size
in: query
required: false
description: Number of application summaries requested per page. The server clamps values to 1–100.
schema:
type: integer
minimum: 1
maximum: 100
default: 21
example: 21
responses:
"200":
description: PartnershipApplication summaries returned successfully.
headers:
Cache-Control:
description: Responses are never stored because administrator review data is returned.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/AdminPartnershipApplicationCollectionData"
example:
items:
- id: pa_0ckcsff4zne3qr4dsrvqk7fckd
applicantUserId: usr_5pvhvpxyhve6ts31n9x8c2y513
state: SUBMITTED
proposal:
type: EXISTING_LISTING_SOURCE
listingSourceId: ls_7h03ebvas3fhj9qb5pr5s22029
approvedPartnershipId: null
approvedListingSourceId: null
created: "2026-09-04T12:00:00Z"
updated: "2026-09-04T12:00:00Z"
size: 21
searchAfter:
- "2026-09-04T12:00:00Z"
- pa_0ckcsff4zne3qr4dsrvqk7fckd
"400":
description: Bad request - invalid query parameters.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
examples:
invalid_state:
summary: Invalid state
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: state
type: QUERY
invalid_proposal_type:
summary: Invalid proposal type
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: proposalType
type: QUERY
invalid_sort:
summary: Invalid sort field
value:
status: 400
title: Bad Request
error: BAD_SORT_VALUE
source:
field: sort
type: QUERY
invalid_order:
summary: Invalid sort order
value:
status: 400
title: Bad Request
error: BAD_ORDER_VALUE
source:
field: order
type: QUERY
invalid_cursor:
summary: Invalid searchAfter cursor
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: searchAfter
type: QUERY
invalid_size:
summary: Invalid page size
value:
status: 400
title: Bad Request
error: BAD_QUERY_PARAMETER_VALUE
source:
field: size
type: QUERY
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Forbidden - this endpoint requires the ADMIN role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"500":
description: Internal authentication or PartnershipApplication search failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"503":
description: Authentication, authorization, or PartnershipApplication data is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
/api/v1/admin/partnership-applications/{partnershipApplicationId}:
get:
summary: Get a PartnershipApplication for administration
description:
"Delegated Aura access tokens require `partnership-applications:read`; missing scope returns `403 FORBIDDEN`. Retrieves a single PartnershipApplication for authenticated administrators.
The response includes the applicant, state, proposal, and nullable approval references. All responses send `Cache-Control: no-store`.
"
operationId: adminGetPartnershipApplication
tags:
- PartnershipApplications
parameters:
- name: partnershipApplicationId
in: path
required: true
description: Unique PartnershipApplication ID for the PartnershipApplication to retrieve.
schema:
type: string
example: pa_0ckcsff4zne3qr4dsrvqk7fckd
security:
- BearerAuth: []
- AccessTokenAuth: []
responses:
"200":
description: PartnershipApplication returned successfully.
headers:
Cache-Control:
description: Caching directive. Always set to `no-store`.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/AdminPartnershipApplicationData"
example:
id: pa_0ckcsff4zne3qr4dsrvqk7fckd
applicantUserId: usr_5pvhvpxyhve6ts31n9x8c2y513
state: APPROVED
proposal:
type: EXISTING_LISTING_SOURCE
listingSourceId: ls_7h03ebvas3fhj9qb5pr5s22029
approvedPartnershipId: psh_4a5zxcsd5tf9wb5mgc4vreb3q7
approvedListingSourceId: ls_7h03ebvas3fhj9qb5pr5s22029
"400":
description: Bad request - invalid PartnershipApplication ID.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Forbidden - this endpoint requires the `ADMIN` role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"404":
description: PartnershipApplication not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"500":
description: Internal server error.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"503":
description: PartnershipApplication data is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
patch:
summary: Mark a PartnershipApplication in review as admin
description: |
Delegated Aura access tokens require `partnership-applications:write`; missing scope returns `403 FORBIDDEN`.
Marks a PartnershipApplication in review for an authenticated administrator.
This operation accepts no request body and only performs the domain-authoritative
`SUBMITTED` to `IN_REVIEW` transition. It does not accept arbitrary state assignment.
The response contains the resulting admin PartnershipApplication representation and
responses always use `Cache-Control: no-store`.
operationId: adminMarkPartnershipApplicationInReview
tags:
- PartnershipApplications
parameters:
- name: partnershipApplicationId
in: path
required: true
description: Unique PartnershipApplication ID for the PartnershipApplication to mark in review.
schema:
type: string
example: pa_0ckcsff4zne3qr4dsrvqk7fckd
security:
- BearerAuth: []
- AccessTokenAuth: []
responses:
"200":
description: PartnershipApplication marked in review successfully.
headers:
Cache-Control:
description: Caching directive. Always set to `no-store`.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/AdminPartnershipApplicationData"
"400":
description: Bad request - invalid PartnershipApplication ID.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Forbidden - this endpoint requires the `ADMIN` role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"404":
description: PartnershipApplication not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"409":
description: Conflict - the PartnershipApplication is not in the Submitted state or was changed concurrently.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"500":
description: Internal authentication or PartnershipApplication transition failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"503":
description: Authentication, authorization, or PartnershipApplication data is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
/api/v1/admin/partnership-applications/{partnershipApplicationId}/decision:
post:
summary: Decide a PartnershipApplication as admin
description: |
Delegated Aura access tokens require `partnership-applications:write`; missing scope returns `403 FORBIDDEN`.
Approves or rejects a PartnershipApplication for an authenticated administrator.
The request accepts only `APPROVE` or `REJECT`; arbitrary state assignment is not supported.
State-changing decisions follow the domain lifecycle and are accepted only from `IN_REVIEW`;
terminal replays retain their existing idempotent behavior. Approval atomically creates or finds
the Party and Partnership, grants membership and
ListingSource access, updates the application, and creates the applicant notification.
Rejection preserves the existing application and notification semantics. Responses always
use `Cache-Control: no-store`.
operationId: adminDecidePartnershipApplication
tags:
- PartnershipApplications
parameters:
- name: partnershipApplicationId
in: path
required: true
description: Unique PartnershipApplication ID for the PartnershipApplication to decide.
schema:
type: string
example: pa_0ckcsff4zne3qr4dsrvqk7fckd
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/DecidePartnershipApplicationData"
security:
- BearerAuth: []
- AccessTokenAuth: []
responses:
"200":
description: PartnershipApplication decided successfully.
headers:
Cache-Control:
description: Caching directive. Always set to `no-store`.
schema:
type: string
example: no-store
content:
application/json:
schema:
$ref: "#/components/schemas/AdminPartnershipApplicationData"
"400":
description: Bad request - invalid PartnershipApplication ID or decision body.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"401":
description: Unauthorized - invalid or missing bearer credentials.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"403":
description: Forbidden - this endpoint requires the `ADMIN` role.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"404":
description: PartnershipApplication or referenced ListingSource not found.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"409":
description: Conflict - the PartnershipApplication is not in a decisionable state or was changed concurrently.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"500":
description: Internal authentication or PartnershipApplication decision failure.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
"503":
description: Authentication, authorization, or PartnershipApplication data is temporarily unavailable.
headers:
Cache-Control:
description: Error responses are never stored.
schema:
type: string
example: no-store
content:
application/problem+json:
schema:
$ref: "#/components/schemas/ApiError"
/api/v1/me/addresses:
post:
summary: Save a private address
operationId: createUserAddress
parameters:
- name: Idempotency-Key
in: header
required: true
description: Opaque owner-scoped creation retry key. Reuse with the original body to recover the server-generated ID. Different keys permit equal-content bookmarks.
schema:
type: string
minLength: 1
maxLength: 128
pattern: '^[A-Za-z0-9_.:-]+$'
tags:
- Users
security:
- BearerAuth: []
- AccessTokenAuth: []
description: Requires the current unsuspended owner. Delegated credentials require users:write. Success and
errors are no-store. The server generates addressId. The body contains label/geography; exactly one valid Idempotency-Key
header identifies retries within this owner. Same-key original creation content returns the same entry's current view (201), including after edits.
Changed creation content or a deleted entry conflicts. Saving does not synchronously geocode or select a preferred address.
responses:
'201':
description: Successful private operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/UserAddress'
'400':
description: Invalid body (BAD_BODY_VALUE), including a caller-supplied addressId, or missing, repeated or invalid Idempotency-Key (BAD_HEADER_VALUE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer credential required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Current user or delegated scope is not permitted (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Address/owner not found (USER_ADDRESS_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale version or conflicting creation key (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (ADDRESS_BOOK_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Storage or transaction unavailable (ADDRESS_BOOK_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserAddress'
get:
summary: Paginate own private addresses
operationId: listUserAddresses
tags:
- Users
security:
- BearerAuth: []
- AccessTokenAuth: []
description: Requires the current unsuspended owner. Delegated credentials require users:read. Success and errors
are no-store. Current geocoding state and eligible accepted results are included using bounded batch hydration.
responses:
'200':
description: Successful private operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/UserAddressPage'
'400':
description: Invalid body, query or strict object ID.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer credential required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Current user or delegated scope is not permitted (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Address/owner not found (USER_ADDRESS_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale version or conflicting creation key (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (ADDRESS_BOOK_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Storage or transaction unavailable (ADDRESS_BOOK_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
parameters:
- in: query
name: after
schema:
$ref: '#/components/schemas/UserAddressId'
- in: query
name: limit
schema:
type: integer
minimum: 1
maximum: 100
default: 25
/api/v1/me/addresses/{address_id}:
get:
summary: Read an own private address
operationId: getUserAddress
tags:
- Users
security:
- BearerAuth: []
- AccessTokenAuth: []
description: 'Requires the current unsuspended owner. Delegated credentials require users:read. Success and
errors are no-store. '
responses:
'200':
description: Successful private operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/UserAddress'
'400':
description: Invalid body, query or strict object ID.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer credential required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Current user or delegated scope is not permitted (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Address/owner not found (USER_ADDRESS_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale version or conflicting creation key (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (ADDRESS_BOOK_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Storage or transaction unavailable (ADDRESS_BOOK_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
parameters:
- in: path
name: address_id
required: true
schema:
$ref: '#/components/schemas/UserAddressId'
put:
summary: Replace an own private address
operationId: updateUserAddress
tags:
- Users
security:
- BearerAuth: []
- AccessTokenAuth: []
description: Requires the current unsuspended owner. Delegated credentials require users:write. Success and
errors are no-store. Full replacement preserves ID. Geographic changes increment inputRevision and fence old
enrichment. Label-only changes preserve resolution input. No-op writes require current version and preserve
versions.
responses:
'200':
description: Successful private operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/UserAddress'
'400':
description: Invalid body, query or strict object ID.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer credential required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Current user or delegated scope is not permitted (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Address/owner not found (USER_ADDRESS_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale version or conflicting creation key (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (ADDRESS_BOOK_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Storage or transaction unavailable (ADDRESS_BOOK_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateUserAddress'
parameters:
- in: path
name: address_id
required: true
schema:
$ref: '#/components/schemas/UserAddressId'
delete:
summary: Erase an own private address
operationId: deleteUserAddress
tags:
- Users
security:
- BearerAuth: []
- AccessTokenAuth: []
description: Requires the current unsuspended owner. Delegated credentials require users:write. Success and
errors are no-store. Erases text/enrichment/pending binding. Deleting the preferred address clears only that
preference atomically; no alternative is selected.
responses:
'204':
description: Successful private operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
'400':
description: Invalid body, query or strict object ID.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer credential required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Current user or delegated scope is not permitted (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Address/owner not found (USER_ADDRESS_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale version or conflicting creation key (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (ADDRESS_BOOK_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Storage or transaction unavailable (ADDRESS_BOOK_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UserAddressExpectedVersion'
parameters:
- in: path
name: address_id
required: true
schema:
$ref: '#/components/schemas/UserAddressId'
/api/v1/me/browsing-destination:
get:
summary: Read own browsing destination
operationId: getBrowsingDestination
tags:
- Users
security:
- BearerAuth: []
- AccessTokenAuth: []
description: Requires the current unsuspended owner. Delegated credentials require users:read. Success and errors
are no-store. An untouched preference has version 1 and NONE.
responses:
'200':
description: Successful private operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/BrowsingDestinationView'
'400':
description: Invalid body, query or strict object ID.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer credential required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Current user or delegated scope is not permitted (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Address/owner not found (USER_ADDRESS_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale version or conflicting creation key (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (ADDRESS_BOOK_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Storage or transaction unavailable (ADDRESS_BOOK_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
put:
summary: Select or clear browsing destination
operationId: setBrowsingDestination
tags:
- Users
security:
- BearerAuth: []
- AccessTokenAuth: []
description: Requires the current unsuspended owner. Delegated credentials require users:write. Success and
errors are no-store. Atomic mutually exclusive preference. NONE clears. ADDRESS must belong to current owner.
COUNTRY_POSTAL needs no full address. At most one address is preferred.
responses:
'200':
description: Successful private operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/BrowsingDestinationView'
'400':
description: Invalid body, query or strict object ID.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer credential required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Current user or delegated scope is not permitted (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Address/owner not found (USER_ADDRESS_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale version or conflicting creation key (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (ADDRESS_BOOK_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Storage or transaction unavailable (ADDRESS_BOOK_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SetBrowsingDestination'
/api/v1/party-locations:
get:
summary: Discover public Party locations
operationId: discoverPartyLocations
tags: [Parties]
security: []
description: >-
Location-oriented discovery of eligible active Party sites. Multiple matching sites of
one Party intentionally appear as separate locations. Country/subdivision predicates
need no coordinates. Radius or distance ordering requires an explicit numeric origin.
Strict proximity requires PREMISES precision; approximate mode retains coarse labels.
Ordered by distance when requested, then native location UUID ascending; otherwise
UUID ascending. Reads current PostgreSQL locations independently of listing projection catch-up.
All responses are private, no-store. Management evidence, addresses and revisions stay private.
parameters:
- name: geography
in: query
required: true
style: deepObject
explode: true
schema:
$ref: '#/components/schemas/GeographicSearchData'
- name: size
in: query
schema: {type: integer, minimum: 1, maximum: 100, default: 21}
- name: searchAfter
in: query
style: deepObject
explode: true
schema:
$ref: '#/components/schemas/PartyLocationDiscoveryCursorData'
responses:
'200':
description: Matching public locations.
content:
application/json:
schema:
type: object
required: [items, size]
properties:
items:
type: array
items: {$ref: '#/components/schemas/PublicPartyLocationData'}
size: {type: integer}
searchAfter: {$ref: '#/components/schemas/PartyLocationDiscoveryCursorData'}
'400':
description: Invalid geographic predicates, origin or continuation (BAD_QUERY_PARAMETER_VALUE).
content:
application/problem+json:
schema: {$ref: '#/components/schemas/ApiError'}
'503':
description: Location read unavailable (PARTY_TEMPORARILY_UNAVAILABLE).
content:
application/problem+json:
schema: {$ref: '#/components/schemas/ApiError'}
/api/v1/parties/{party_id}/locations:
post:
operationId: createPartyLocation
summary: Create a Party location
tags:
- Party
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: party_id
in: path
required: true
schema:
type: string
pattern: ^pty_
description: Strict Party TypeID.
- name: Idempotency-Key
in: header
required: true
schema:
type: string
minLength: 1
maxLength: 128
pattern: ^[A-Za-z0-9_.:-]+$
description: Exactly one key. Stable per Party and trusted caller identity; matching retries converge, conflicting
command reuse returns 409.
responses:
'201':
description: Created location; matching retries replay the original creation result.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
Location:
schema:
type: string
description: Protected PartyLocation detail path.
content:
application/json:
schema:
$ref: '#/components/schemas/PartyLocationData'
'400':
description: Invalid body/header/path/query (BAD_BODY_VALUE, BAD_HEADER_VALUE, INVALID_OBJECT_ID or BAD_QUERY_PARAMETER_VALUE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Party or eligible location not found (PARTY_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence/transaction unavailable (PARTY_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (PARTY_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing credential scope or Party-location management authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale or exhausted revision, retired-site correction or conflicting idempotency reuse (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
description: Delegated credentials require parties:write. Use cases require administrator/internal authority,
membership in this Party's active partnership, or an explicit location management grant.
Non-administrator users must be unsuspended. Membership removal or partnership dissolution removes derived
authority; independent explicit grants survive. Listing-write scope does not confer access.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePartyLocationData'
get:
operationId: listPartyLocations
summary: List protected Party locations
tags:
- Party
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: party_id
in: path
required: true
schema:
type: string
pattern: ^pty_
description: Strict Party TypeID.
- name: after
in: query
schema:
$ref: '#/components/schemas/PartyLocationId'
description: Exclusive ascending UUID keyset continuation; use previous next in the same Party/view.
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 100
default: 25
responses:
'200':
description: Successful PartyLocation operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/PartyLocationsPage'
'400':
description: Invalid body/header/path/query (BAD_BODY_VALUE, BAD_HEADER_VALUE, INVALID_OBJECT_ID or BAD_QUERY_PARAMETER_VALUE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Party or eligible location not found (PARTY_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence/transaction unavailable (PARTY_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (PARTY_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing credential scope or Party-location management authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
description: Delegated credentials require parties:read. Use cases require administrator/internal authority,
membership in this Party's active partnership, or an explicit location management grant.
Non-administrator users must be unsuspended. Membership removal or partnership dissolution removes derived
authority; independent explicit grants survive. Listing-write scope does not confer access.
/api/v1/parties/{party_id}/locations/{location_id}:
get:
operationId: getPartyLocation
summary: Get a protected Party location
tags:
- Party
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: party_id
in: path
required: true
schema:
type: string
pattern: ^pty_
description: Strict Party TypeID.
- name: location_id
in: path
required: true
schema:
$ref: '#/components/schemas/PartyLocationId'
responses:
'200':
description: Successful PartyLocation operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/PartyLocationData'
'400':
description: Invalid body/header/path/query (BAD_BODY_VALUE, BAD_HEADER_VALUE, INVALID_OBJECT_ID or BAD_QUERY_PARAMETER_VALUE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Party or eligible location not found (PARTY_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence/transaction unavailable (PARTY_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (PARTY_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing credential scope or Party-location management authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
description: Delegated credentials require parties:read. Use cases require administrator/internal authority,
membership in this Party's active partnership, or an explicit location management grant.
Non-administrator users must be unsuspended. Membership removal or partnership dissolution removes derived
authority; independent explicit grants survive. Listing-write scope does not confer access.
patch:
operationId: correctPartyLocation
summary: Correct the same identified site
tags:
- Party
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: party_id
in: path
required: true
schema:
type: string
pattern: ^pty_
description: Strict Party TypeID.
- name: location_id
in: path
required: true
schema:
$ref: '#/components/schemas/PartyLocationId'
responses:
'200':
description: Successful PartyLocation operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/PartyLocationData'
'400':
description: Invalid body/header/path/query (BAD_BODY_VALUE, BAD_HEADER_VALUE, INVALID_OBJECT_ID or BAD_QUERY_PARAMETER_VALUE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Party or eligible location not found (PARTY_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence/transaction unavailable (PARTY_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (PARTY_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing credential scope or Party-location management authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale or exhausted revision, retired-site correction or conflicting idempotency reuse (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
description: Delegated credentials require parties:write. Use cases require administrator/internal authority,
membership in this Party's active partnership, or an explicit location management grant.
Non-administrator users must be unsuspended. Membership removal or partnership dissolution removes derived
authority; independent explicit grants survive. Listing-write scope does not confer access.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CorrectPartyLocationData'
/api/v1/parties/{party_id}/locations/{location_id}/lifecycle:
put:
operationId: setPartyLocationLifecycle
summary: Retire or explicitly restore a Party location
tags:
- Party
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: party_id
in: path
required: true
schema:
type: string
pattern: ^pty_
description: Strict Party TypeID.
- name: location_id
in: path
required: true
schema:
$ref: '#/components/schemas/PartyLocationId'
responses:
'200':
description: Successful PartyLocation operation.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/PartyLocationData'
'400':
description: Invalid body/header/path/query (BAD_BODY_VALUE, BAD_HEADER_VALUE, INVALID_OBJECT_ID or BAD_QUERY_PARAMETER_VALUE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Party or eligible location not found (PARTY_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence/transaction unavailable (PARTY_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (PARTY_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing credential scope or Party-location management authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale or exhausted revision, retired-site correction or conflicting idempotency reuse (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
description: Delegated credentials require parties:write. Use cases require administrator/internal authority,
membership in this Party's active partnership, or an explicit location management grant.
Non-administrator users must be unsuspended. Membership removal or partnership dissolution removes derived
authority; independent explicit grants survive. Listing-write scope does not confer access.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SetPartyLocationLifecycleData'
/api/v1/admin/parties/{party_id}/location-managers/{user_id}:
put:
operationId: setPartyLocationManagementGrant
summary: Grant or revoke Party location management
tags:
- Party
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: party_id
in: path
required: true
schema:
type: string
pattern: ^pty_
description: Strict Party TypeID.
- name: user_id
in: path
required: true
schema:
type: string
pattern: ^usr_
responses:
'400':
description: Invalid body/header/path/query (BAD_BODY_VALUE, BAD_HEADER_VALUE, INVALID_OBJECT_ID or BAD_QUERY_PARAMETER_VALUE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Party or eligible location not found (PARTY_NOT_FOUND).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence/transaction unavailable (PARTY_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (PARTY_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing credential scope or administrator authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale or exhausted revision, retired-site correction or conflicting idempotency reuse (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'204':
description: Grant state applied.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
description: Administrator/internal callers only, including parties:write for delegated credentials. An ordinary
location manager cannot grant privileges. Revocation serializes against protected location operations.
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PartyLocationManagementGrantData'
/api/v1/listing-sources/{listing_source_id}/location-default:
get:
summary: Get source location default
operationId: getSourceLocationDefault
tags:
- ListingSources
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: listing_source_id
in: path
required: true
schema:
type: string
description: Strict ls_ UUIDv7 ListingSource TypeID.
description: Requires an unsuspended administrator, or membership in the operator
Party active partnership with this exact source grant. Trusted service/system
use cases are also supported. Delegated callers additionally need listing-sources:read.
Assignment does not mutate Party locations or attribute a listing seller. Protected
reads retain private/retired references for traceability but return no location
address/point. All responses are no-store. Current-revision no-ops preserve
revisions; stale retries conflict.
responses:
'200':
description: Protected default configuration with evidence and expected-revision
token, without a copied location address or point.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/SourceLocationDefaultData'
'400':
description: Invalid body/path (BAD_BODY_VALUE or INVALID_OBJECT_ID).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing scope or current source management authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Source (LISTING_SOURCE_NOT_FOUND) or operator-owned location
(PARTY_NOT_FOUND) does not exist.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale/exhausted revision, retired selection or applicability
change without an assignment (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (LISTING_SOURCE_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence or transaction unavailable (LISTING_SOURCE_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
put:
summary: Assign or replace source location default
operationId: assignSourceLocationDefault
tags:
- ListingSources
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: listing_source_id
in: path
required: true
schema:
type: string
description: Strict ls_ UUIDv7 ListingSource TypeID.
description: Requires an unsuspended administrator, or membership in the operator
Party active partnership with this exact source grant. Trusted service/system
use cases are also supported. Delegated callers additionally need listing-sources:write.
Assignment does not mutate Party locations or attribute a listing seller. Protected
reads retain private/retired references for traceability but return no location
address/point. All responses are no-store. Current-revision no-ops preserve
revisions; stale retries conflict.
responses:
'200':
description: Protected default configuration with evidence and expected-revision
token, without a copied location address or point.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/SourceLocationDefaultData'
'400':
description: Invalid body/path (BAD_BODY_VALUE or INVALID_OBJECT_ID).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing scope or current source management authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Source (LISTING_SOURCE_NOT_FOUND) or operator-owned location
(PARTY_NOT_FOUND) does not exist.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale/exhausted revision, retired selection or applicability
change without an assignment (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (LISTING_SOURCE_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence or transaction unavailable (LISTING_SOURCE_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AssignSourceLocationDefaultData'
patch:
summary: Change source location applicability
operationId: changeSourceLocationDefaultApplicability
tags:
- ListingSources
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: listing_source_id
in: path
required: true
schema:
type: string
description: Strict ls_ UUIDv7 ListingSource TypeID.
description: Requires an unsuspended administrator, or membership in the operator
Party active partnership with this exact source grant. Trusted service/system
use cases are also supported. Delegated callers additionally need listing-sources:write.
Assignment does not mutate Party locations or attribute a listing seller. Protected
reads retain private/retired references for traceability but return no location
address/point. All responses are no-store. Current-revision no-ops preserve
revisions; stale retries conflict.
responses:
'200':
description: Protected default configuration with evidence and expected-revision
token, without a copied location address or point.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/SourceLocationDefaultData'
'400':
description: Invalid body/path (BAD_BODY_VALUE or INVALID_OBJECT_ID).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing scope or current source management authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Source (LISTING_SOURCE_NOT_FOUND) or operator-owned location
(PARTY_NOT_FOUND) does not exist.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale/exhausted revision, retired selection or applicability
change without an assignment (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (LISTING_SOURCE_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence or transaction unavailable (LISTING_SOURCE_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ChangeSourceLocationDefaultApplicabilityData'
delete:
summary: Clear source location default
operationId: clearSourceLocationDefault
tags:
- ListingSources
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: listing_source_id
in: path
required: true
schema:
type: string
description: Strict ls_ UUIDv7 ListingSource TypeID.
description: Requires an unsuspended administrator, or membership in the operator
Party active partnership with this exact source grant. Trusted service/system
use cases are also supported. Delegated callers additionally need listing-sources:write.
Assignment does not mutate Party locations or attribute a listing seller. Protected
reads retain private/retired references for traceability but return no location
address/point. All responses are no-store. Current-revision no-ops preserve
revisions; stale retries conflict.
responses:
'200':
description: Protected default configuration with evidence and expected-revision
token, without a copied location address or point.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/SourceLocationDefaultData'
'400':
description: Invalid body/path (BAD_BODY_VALUE or INVALID_OBJECT_ID).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing scope or current source management authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Source (LISTING_SOURCE_NOT_FOUND) or operator-owned location
(PARTY_NOT_FOUND) does not exist.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale/exhausted revision, retired selection or applicability
change without an assignment (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (LISTING_SOURCE_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence or transaction unavailable (LISTING_SOURCE_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ClearSourceLocationDefaultData'
/api/v1/admin/listing-sources/{listing_source_id}/location-default:
get:
summary: Get source location default as administrator
operationId: adminGetSourceLocationDefault
tags:
- ListingSources
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: listing_source_id
in: path
required: true
schema:
type: string
description: Strict ls_ UUIDv7 ListingSource TypeID.
description: Requires an unsuspended administrator. Operator-partnership membership
or a source grant alone does not authorize this admin route. Trusted service/system
use cases are also supported. Delegated callers additionally need listing-sources:read.
Assignment does not mutate Party locations or attribute a listing seller. Protected
reads retain private/retired references for traceability but return no location
address/point. All responses are no-store. Current-revision no-ops preserve
revisions; stale retries conflict.
responses:
'200':
description: Protected default configuration with evidence and expected-revision
token, without a copied location address or point.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/SourceLocationDefaultData'
'400':
description: Invalid body/path (BAD_BODY_VALUE or INVALID_OBJECT_ID).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing scope or current unsuspended administrator authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Source (LISTING_SOURCE_NOT_FOUND) or operator-owned location
(PARTY_NOT_FOUND) does not exist.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale/exhausted revision, retired selection or applicability
change without an assignment (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (LISTING_SOURCE_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence or transaction unavailable (LISTING_SOURCE_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
put:
summary: Assign or replace source location default as administrator
operationId: adminAssignSourceLocationDefault
tags:
- ListingSources
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: listing_source_id
in: path
required: true
schema:
type: string
description: Strict ls_ UUIDv7 ListingSource TypeID.
description: Requires an unsuspended administrator. Operator-partnership membership
or a source grant alone does not authorize this admin route. Trusted service/system
use cases are also supported. Delegated callers additionally need listing-sources:write.
Assignment does not mutate Party locations or attribute a listing seller. Protected
reads retain private/retired references for traceability but return no location
address/point. All responses are no-store. Current-revision no-ops preserve
revisions; stale retries conflict.
responses:
'200':
description: Protected default configuration with evidence and expected-revision
token, without a copied location address or point.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/SourceLocationDefaultData'
'400':
description: Invalid body/path (BAD_BODY_VALUE or INVALID_OBJECT_ID).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing scope or current unsuspended administrator authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Source (LISTING_SOURCE_NOT_FOUND) or operator-owned location
(PARTY_NOT_FOUND) does not exist.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale/exhausted revision, retired selection or applicability
change without an assignment (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (LISTING_SOURCE_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence or transaction unavailable (LISTING_SOURCE_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/AssignSourceLocationDefaultData'
patch:
summary: Change source location applicability as administrator
operationId: adminChangeSourceLocationDefaultApplicability
tags:
- ListingSources
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: listing_source_id
in: path
required: true
schema:
type: string
description: Strict ls_ UUIDv7 ListingSource TypeID.
description: Requires an unsuspended administrator. Operator-partnership membership
or a source grant alone does not authorize this admin route. Trusted service/system
use cases are also supported. Delegated callers additionally need listing-sources:write.
Assignment does not mutate Party locations or attribute a listing seller. Protected
reads retain private/retired references for traceability but return no location
address/point. All responses are no-store. Current-revision no-ops preserve
revisions; stale retries conflict.
responses:
'200':
description: Protected default configuration with evidence and expected-revision
token, without a copied location address or point.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/SourceLocationDefaultData'
'400':
description: Invalid body/path (BAD_BODY_VALUE or INVALID_OBJECT_ID).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing scope or current unsuspended administrator authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Source (LISTING_SOURCE_NOT_FOUND) or operator-owned location
(PARTY_NOT_FOUND) does not exist.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale/exhausted revision, retired selection or applicability
change without an assignment (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (LISTING_SOURCE_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence or transaction unavailable (LISTING_SOURCE_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ChangeSourceLocationDefaultApplicabilityData'
delete:
summary: Clear source location default as administrator
operationId: adminClearSourceLocationDefault
tags:
- ListingSources
security:
- BearerAuth: []
- AccessTokenAuth: []
parameters:
- name: listing_source_id
in: path
required: true
schema:
type: string
description: Strict ls_ UUIDv7 ListingSource TypeID.
description: Requires an unsuspended administrator. Operator-partnership membership
or a source grant alone does not authorize this admin route. Trusted service/system
use cases are also supported. Delegated callers additionally need listing-sources:write.
Assignment does not mutate Party locations or attribute a listing seller. Protected
reads retain private/retired references for traceability but return no location
address/point. All responses are no-store. Current-revision no-ops preserve
revisions; stale retries conflict.
responses:
'200':
description: Protected default configuration with evidence and expected-revision
token, without a copied location address or point.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/json:
schema:
$ref: '#/components/schemas/SourceLocationDefaultData'
'400':
description: Invalid body/path (BAD_BODY_VALUE or INVALID_OBJECT_ID).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'401':
description: Bearer authentication required (INVALID_CREDENTIALS).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'403':
description: Missing scope or current unsuspended administrator authority (FORBIDDEN).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'404':
description: Source (LISTING_SOURCE_NOT_FOUND) or operator-owned location
(PARTY_NOT_FOUND) does not exist.
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'409':
description: Stale/exhausted revision, retired selection or applicability
change without an assignment (CONFLICT).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'500':
description: Invalid persisted state or internal failure (LISTING_SOURCE_INTERNAL_ERROR).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
'503':
description: Persistence or transaction unavailable (LISTING_SOURCE_TEMPORARILY_UNAVAILABLE).
headers:
Cache-Control:
schema:
type: string
enum:
- no-store
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ApiError'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ClearSourceLocationDefaultData'
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: "Cognito JWT bearer token.
This scheme is used for authenticated user routes and for partner routes that accept Cognito user tokens.
"
AccessTokenAuth:
type: http
scheme: bearer
bearerFormat: opaque
description:
"Aura Historia bearer access token created through `/api/v1/me/access-tokens`.
Tokens are sent as standard bearer authorization headers.
Selected partner routes accept this scheme instead of the removed partner API-key flow.
"
parameters:
AsyncProductListingIdempotencyKey:
name: Idempotency-Key
in: header
required: false
description: One value only; native duplicates and comma-joined values are invalid (`400 BAD_HEADER_VALUE`) before publication. Use 1–128 visible ASCII bytes excluding comma. Supply the same key with the unchanged ordered batch for transport retries. If absent, a key is generated and returned on evaluated reports; it cannot be recovered if that response is lost.
schema:
type: string
minLength: 1
maxLength: 128
pattern: '^[\x21-\x2B\x2D-\x7E]{1,128}$'
example: catalog-sync-2026-09-29
ProductListingIdPath:
name: productListingId
in: path
required: true
description: Strict `pl_` UUIDv7 ProductListing TypeID.
schema: { type: string }
headers:
AsyncProductListingIdempotencyKey:
description: Effective key, echoed on every evaluated report (including non-2xx); not guaranteed on pre-evaluation ApiError responses. CORS-exposed for browser clients.
schema:
type: string
minLength: 1
maxLength: 128
pattern: '^[\x21-\x2B\x2D-\x7E]{1,128}$'
example: catalog-sync-2026-09-29
schemas:
ActorData:
oneOf:
- type: string
enum:
- SYSTEM
description: Backend-initiated actor marker.
- type: string
description: User ID of the user who performed the change.
description: "Audit actor encoded as a plain string.
Values are either the literal `SYSTEM` or the User ID of the acting user.
"
example: SYSTEM
ProductListingSummaryData:
type: object
description: Lightweight ProductListing summary for search and similar-listing results.
required:
- productListingId
- eventId
- source
- sourceListingId
- priceValuation
- availability
- lifecycle
- url
- viewUrl
- images
- updated
properties:
productListingId:
type: string
productListingTitleSlugId:
type: string
minLength: 8
maxLength: 120
pattern: "^[a-z0-9]+(-[a-z0-9]+)*-[0-9a-f]{6}$"
description: Immutable Aura-owned public locator. Omitted when the listing is redacted as hidden.
example: museum-cabinet-18-19-century-a1b2c3
eventId:
type: string
source:
$ref: "#/components/schemas/ProductListingSourceData"
sourceListingId:
type: string
auctionId:
type: string
description: Indexed Auction TypeID association. Omitted when this listing has no Auction association; search and similar results do not hydrate current Auction metadata.
title:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
displayPrice:
allOf:
- $ref: "#/components/schemas/ProductListingPriceData"
nullable: true
priceValuation:
$ref: "#/components/schemas/ProductListingSummaryPriceValuationData"
availability:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
lifecycle:
$ref: "#/components/schemas/ListingLifecycleData"
url:
type: string
format: uri
viewUrl:
type: string
format: uri
images:
type: array
items:
$ref: "#/components/schemas/ProductListingImageData"
contentPolicy:
allOf:
- $ref: "#/components/schemas/ContentPolicyData"
nullable: true
updated:
type: string
format: date-time
geography:
description: Advertised inventory geography on geographic search summaries; selected by the backend from eligible source evidence.
allOf: [{$ref: '#/components/schemas/ListingGeographyData'}]
ProductListingSummaryPriceValuationData:
oneOf:
- type: object
required:
- type
- fxRateId
- capturedAt
properties:
type:
type: string
enum:
- CURRENT
fxRateId:
type: string
capturedAt:
type: string
format: date-time
- type: object
required:
- type
- fxRateId
- observedAt
properties:
type:
type: string
enum:
- SALE_OBSERVATION
fxRateId:
type: string
observedAt:
type: string
format: date-time
ProductListingDetailsData:
type: object
description: Canonical ProductListing detail inside a personalized response wrapper.
required:
- productListingId
- eventId
- source
- sourceListingId
- pricing
- availability
- lifecycle
- url
- viewUrl
- images
- auction
- lot
- created
- updated
properties:
productListingId:
type: string
productListingTitleSlugId:
type: string
minLength: 8
maxLength: 120
pattern: "^[a-z0-9]+(-[a-z0-9]+)*-[0-9a-f]{6}$"
description: Immutable Aura-owned public locator. Omitted when the listing is redacted as hidden.
example: museum-cabinet-18-19-century-a1b2c3
eventId:
type: string
source:
$ref: "#/components/schemas/ProductListingSourceData"
sourceListingId:
type: string
productTitle:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
description: Original normalized title. Truncation ellipses remain stable; legacy constructor trailing whitespace is presented trimmed.
productDescription:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
title:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
description:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
pricing:
type: object
required:
- source
- display
- valuation
properties:
source:
$ref: "#/components/schemas/ProductListingPricingData"
display:
$ref: "#/components/schemas/ProductListingPricingData"
valuation:
$ref: "#/components/schemas/ProductListingPricingValuationData"
availability:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
lifecycle:
$ref: "#/components/schemas/ListingLifecycleData"
url:
type: string
format: uri
viewUrl:
type: string
format: uri
images:
type: array
items:
$ref: "#/components/schemas/ProductListingImageData"
contentPolicy:
allOf:
- $ref: "#/components/schemas/ContentPolicyData"
nullable: true
auction:
allOf:
- $ref: "#/components/schemas/AuctionSummaryData"
nullable: true
description: Current parent Auction presentation from the joined PostgreSQL detail read. Null when the listing has no parent Auction.
lot:
allOf:
- $ref: "#/components/schemas/ProductListingLotData"
nullable: true
description: Listing-owned lot facts. Null when the listing has no lot facts.
created:
type: string
format: date-time
updated:
type: string
format: date-time
ProductListingLotData:
type: object
additionalProperties: false
required:
[
lotNumber,
cataloguePosition,
biddingOpens,
scheduledCloses,
reportedClosedAt,
]
description: Listing-owned lot facts. These facts may exist without a parent Auction.
properties:
lotNumber:
type: string
nullable: true
cataloguePosition:
type: integer
format: int64
minimum: 1
maximum: 4294967295
nullable: true
biddingOpens:
type: string
format: date-time
nullable: true
scheduledCloses:
type: string
format: date-time
nullable: true
reportedClosedAt:
type: string
format: date-time
nullable: true
ProductListingPricingData:
type: object
properties:
price:
allOf:
- $ref: "#/components/schemas/ProductListingPriceData"
nullable: true
priceEstimateMin:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
priceEstimateMax:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
ProductListingPricingValuationData:
oneOf:
- type: object
required:
- type
- fxRateId
- capturedAt
properties:
type:
type: string
enum:
- CURRENT
fxRateId:
type: string
capturedAt:
type: string
format: date-time
- type: object
required:
- type
- fxRateId
- capturedAt
- observedAt
properties:
type:
type: string
enum:
- SALE_OBSERVATION
fxRateId:
type: string
capturedAt:
type: string
format: date-time
observedAt:
type: string
format: date-time
PersonalizedProductListingDetailsData:
type: object
description: Canonical Product detail with optional user-specific state.
required:
- item
properties:
item:
$ref: "#/components/schemas/ProductListingDetailsData"
userState:
allOf:
- $ref: "#/components/schemas/ProductListingUserStateData"
nullable: true
description: Present only for a valid user or delegated-user bearer token.
PersonalizedProductListingSummaryData:
type: object
description: Canonical Product summary with optional user-specific state.
required:
- item
properties:
item:
$ref: "#/components/schemas/ProductListingSummaryData"
userState:
allOf:
- $ref: "#/components/schemas/ProductListingUserStateData"
nullable: true
description: Present only for a valid user or delegated-user bearer token.
ProductListingSearchResultData:
type: object
description: Cursor-paged canonical Product search response.
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/PersonalizedProductListingSummaryData"
description: Personalized Product summaries in OpenSearch result order.
size:
type: integer
minimum: 0
maximum: 100
description: Number of items returned in the current page.
example: 21
total:
type: integer
minimum: 0
nullable: true
description:
Total matching product-listings for BM25 search when the backend provides it. Hybrid BM25 plus KNN
search omits this value because its fused candidate pool is not a reliable total.
example: 127
searchAfter:
allOf:
- $ref: "#/components/schemas/ProductListingSearchCursorData"
nullable: true
description: Opaque cursor for the next page. It must be sent back as one JSON-encoded `searchAfter` query value.
ProductListingSearchCursorData:
type: object
required:
- fxRateId
- searchAfter
properties:
fxRateId:
type: string
description: Persisted FX snapshot used for active Product filtering and display values in this cursor chain.
searchAfter:
type: array
items: {}
description: Internal OpenSearch continuation token.
example:
fxRateId: fx_0cwktgjtwnf4tb6hf2f8zm0x5k
searchAfter:
- 2999
- pl_5xdb465tg1enarx2knf04mxbxj
ProductListingUserStateData:
type: object
description: User-specific state information for a product
required:
- watchlist
- contentVisibility
- notification
- searchFilter
properties:
watchlist:
$ref: "#/components/schemas/WatchlistUserStateData"
contentVisibility:
$ref: "#/components/schemas/ContentVisibilityUserStateData"
notification:
$ref: "#/components/schemas/NotificationUserStateData"
searchFilter:
$ref: "#/components/schemas/SearchFilterUserStateData"
WatchlistUserStateData:
type: object
description: Watchlist-specific user state for a product
required:
- watching
- notifications
properties:
watching:
type: boolean
description: Whether the product is on the user's watchlist
example: true
notifications:
type: boolean
description: Whether notifications are enabled for this watchlist product
example: false
ContentVisibilityUserStateData:
type: object
description: Stored viewer preference used when presenting unassessed or sensitive listing content.
required:
- showUnassessedOrSensitiveContent
properties:
showUnassessedOrSensitiveContent:
type: boolean
description: Whether unassessed or sensitive content may be shown to this viewer.
example: false
NotificationUserStateData:
type: object
description: Unseen notification IDs for this product, ordered newest first.
required:
- unseenNotificationIds
properties:
unseenNotificationIds:
type: array
description: Every unseen Notification ID for this product. Empty when none exist.
default: []
items:
type: string
SearchFilterUserStateData:
type: object
description: "User's saved-search-filter match state for a product.
When `matched` is `true`, at least one of the user's saved search filters matched this product.
`userSearchFilterId`, `userSearchFilterName`, and `matchFeedback` are only
present when `matched` is `true`.
Defaults to `matched: false` when the user has no saved search filters or none of them matched.
When `hidden` is `true`, the match exceeds the user's monthly search-filter match quota and the
product data is anonymized (valid synthetic object IDs, placeholder title, unknown enums, nulled timestamps).
Only matches ranked beyond the quota (by ascending match creation time) are hidden;
the first N matches (where N is the user's tier quota) remain fully visible.
"
required:
- matched
- hidden
properties:
matched:
type: boolean
description: Whether any of the user's saved search filters matched this product. Defaults to `false`.
default: false
example: true
hidden:
type: boolean
description:
"Whether this match is hidden because the user has exceeded their monthly search-filter match quota.
When `true`, the product data in the response is anonymized: object-ID fields are replaced with valid synthetic IDs using their documented prefixes,
the title becomes a language-specific placeholder, enum fields are set to their unknown variants, optional fields are omitted, and
timestamps are set to the Unix epoch.
Defaults to `false`.
"
default: false
example: false
userSearchFilterId:
type: string
description:
"The ID of the saved search filter that matched this product.
Present only when `matched` is `true`; omitted otherwise.
"
example: sf_4hyqf0gyxveazss7nby5hve5x2
userSearchFilterName:
type: string
description:
"The user-defined name of the saved search filter that matched this product.
Present only when `matched` is `true`; omitted otherwise.
"
example: Vintage Art Deco
matchFeedback:
type: boolean
description:
"Optional feedback previously recorded by the authenticated user for this saved-search match.
Present only when `matched` is `true` and feedback has been explicitly stored for the match.
`true` marks the match as relevant, `false` marks it as not relevant.
"
example: true
LocalizedTextData:
type: object
description: Text content with language information
required:
- text
- language
properties:
text:
type: string
description: The text content
language:
$ref: "#/components/schemas/LanguageData"
PriceData:
type: object
description: Price information with currency
required:
- currency
- amount
properties:
currency:
$ref: "#/components/schemas/CurrencyData"
amount:
type: integer
description: Price amount in minor currency units (e.g., cents for most supported currencies, whole yen for JPY)
minimum: 0
example: 2999
ProductListingPriceData:
oneOf:
- type: object
required:
- type
- currency
- amount
additionalProperties: false
properties:
type:
type: string
enum: [MONETARY]
currency:
$ref: "#/components/schemas/CurrencyData"
amount:
type: integer
minimum: 0
- type: object
required:
- type
additionalProperties: false
properties:
type:
type: string
enum: [ON_REQUEST]
ProductListingHistoryPriceDisplayData:
allOf:
- $ref: "#/components/schemas/PriceData"
- type: object
required:
- fxRateId
- capturedAt
properties:
fxRateId:
type: string
description: Immutable FX snapshot selected at or before the entry timestamp.
capturedAt:
type: string
format: date-time
description: Capture time of that snapshot, never after the history entry timestamp.
description: HalfUp display amount in requested currency minor units (JPY/KRW 0 decimals, others 2). Omitted when the snapshot or a required quote is unavailable, including in a complete legacy 19-currency snapshot.
ProductListingHistoryEstimateData:
allOf:
- $ref: "#/components/schemas/PriceData"
- type: object
properties:
display:
$ref: "#/components/schemas/ProductListingHistoryPriceDisplayData"
description: Unchanged source estimate with optional historical display projection.
ProductListingHistoryMainPriceData:
oneOf:
- type: object
required:
- type
- currency
- amount
additionalProperties: false
properties:
type:
type: string
enum: [MONETARY]
currency:
$ref: "#/components/schemas/CurrencyData"
amount:
type: integer
minimum: 0
display:
$ref: "#/components/schemas/ProductListingHistoryPriceDisplayData"
- type: object
required:
- type
additionalProperties: false
properties:
type:
type: string
enum: [ON_REQUEST]
description: Unchanged source main price; only monetary values can have historical display projections.
ProductListingHistoryPricingData:
type: object
properties:
price:
allOf:
- $ref: "#/components/schemas/ProductListingHistoryMainPriceData"
nullable: true
priceEstimateMin:
allOf:
- $ref: "#/components/schemas/ProductListingHistoryEstimateData"
nullable: true
priceEstimateMax:
allOf:
- $ref: "#/components/schemas/ProductListingHistoryEstimateData"
nullable: true
ProductListingHistoryEntryData:
type: object
description: One immutable committed ProductListing domain-history entry.
required:
- eventType
- productListingId
- eventId
- payload
- timestamp
properties:
eventType:
$ref: "#/components/schemas/ProductListingHistoryEntryTypeData"
productListingId:
type: string
description: Unique internal ProductListing identifier
eventId:
type: string
description: Unique identifier for this committed event
payload:
$ref: "#/components/schemas/ProductListingHistoryPayloadData"
timestamp:
type: string
format: date-time
description: When the event occurred (RFC3339 format)
LanguageData:
type: string
enum:
- de
- en
- fr
- es
- it
- zh
- pt
- pl
- tr
- nl
- cs
- ja
- ru
- ar
description: "Supported language codes (ISO 639-1 canonical values):
- de: German (includes de-DE, de-AT, de-CH, de-LU, de-LI)
- en: English (includes en-US, en-GB, en-AU, en-CA, en-NZ, and backend-specific accepted alias en_IE)
- fr: French (includes fr-FR, fr-CA, fr-BE, fr-CH, fr-LU)
- es: Spanish (includes es-ES, es-MX, es-AR, es-CO, es-CL, es-PE, es-VE)
- it: Italian (includes it-IT, it-CH)
- zh: Chinese (Simplified) (includes zh-CN, zh-Hans)
- pt: Portuguese (includes pt-PT, pt-BR)
- pl: Polish (includes pl-PL)
- tr: Turkish (includes tr-TR)
- nl: Dutch (includes nl-NL, nl-BE)
- cs: Czech (includes cs-CZ)
- ja: Japanese (includes ja-JP)
- ru: Russian (includes ru-RU)
- ar: Arabic (includes ar-SA, ar-EG, ar-AE)
`de`, `en`, `fr`, `es`, and `it` are fully supported localization/translation-target languages.
`zh`, `pt`, `pl`, `tr`, `nl`, `cs`, `ja`, `ru`, and `ar` are ingestion-only languages:
they can appear in stored/native content and are accepted anywhere `LanguageData` is used,
but backend-generated translations and fallback localized strings are not produced in these languages.
"
default: en
example: de
CurrencyData:
type: string
enum:
- EUR
- GBP
- USD
- AUD
- CAD
- NZD
- CNY
- BRL
- PLN
- TRY
- JPY
- CZK
- RUB
- AED
- SAR
- HKD
- SGD
- CHF
- ZAR
- SEK
- DKK
- NOK
- KRW
- INR
- TWD
- HUF
- RON
- MXN
- THB
description: "Supported currencies (ISO 4217 codes):
- EUR: Euro
- GBP: British Pound
- USD: US Dollar
- AUD: Australian Dollar
- CAD: Canadian Dollar
- NZD: New Zealand Dollar
- CNY: Chinese Yuan
- BRL: Brazilian Real
- PLN: Polish Złoty
- TRY: Turkish Lira
- JPY: Japanese Yen
- CZK: Czech Koruna
- RUB: Russian Ruble
- AED: UAE Dirham
- SAR: Saudi Riyal
- HKD: Hong Kong Dollar
- SGD: Singapore Dollar
- CHF: Swiss Franc
- ZAR: South African Rand
- SEK: Swedish Krona
- DKK: Danish Krone
- NOK: Norwegian Krone
- KRW: South Korean Won
- INR: Indian Rupee
- TWD: New Taiwan Dollar
- HUF: Hungarian Forint
- RON: Romanian Leu
- MXN: Mexican Peso
- THB: Thai Baht
"
default: EUR
example: EUR
MeasurementUnitData:
type: string
enum:
- METRIC
- IMPERIAL
description: "User preference for distance/size presentation:
- METRIC: Metric units.
- IMPERIAL: Imperial units.
"
default: METRIC
example: METRIC
ListingAvailabilityData:
type: string
enum:
- AVAILABLE
- IN_STOCK
- LIMITED_AVAILABILITY
- BACK_ORDER
- MADE_TO_ORDER
- PRE_ORDER
- PRE_SALE
- UNAVAILABLE
- RESERVED
- OUT_OF_STOCK
- SOLD_OUT
description:
Current reliable source assertion of listing purchase availability. Omitted or `null` means Aura has no
reliable current assertion.
example: IN_STOCK
ListingOrderabilityData:
type: string
enum:
- ORDERABLE_NOW
- ORDERABLE_CONDITIONALLY
- NOT_ORDERABLE
description: Broad classification derived from a concrete availability assertion; it is not independently stored.
example: ORDERABLE_NOW
ListingLifecycleData:
type: string
enum:
- ACTIVE
- WITHDRAWN
description: "Source-catalog membership of a ProductListing:
- ACTIVE: The listing is currently offered by its authoritative source.
- WITHDRAWN: The listing is retained for history but is no longer offered.
"
example: ACTIVE
ProductListingAuctionData:
type: object
additionalProperties: false
description: Partner ProductListing nested write patch. `auctionId` must identify an existing Auction for the same ListingSource. Omit it to preserve membership, send null to clear membership, or send a value to set it. Omit a lot/timing leaf to preserve it, send null to clear a clearable leaf, or send a value to set it.
properties:
auctionId:
type: string
nullable: true
description: Existing same-ListingSource Aura Auction TypeID. Omit to preserve membership; send null to clear it.
example: auc_01jgfjjz4ne2g0000000000000
lotNumber:
type: string
maxLength: 128
nullable: true
description: Omit to preserve the lot label; send null to clear it; send a value to set it.
example: "42A"
cataloguePosition:
type: integer
format: int64
minimum: 1
maximum: 4294967295
nullable: true
description: Omit to preserve the catalogue position; send null to clear it; send a value to set it.
example: 7
timing:
allOf:
- $ref: "#/components/schemas/ProductListingAuctionTimesData"
nullable: true
ProductListingAuctionFactsData:
type: object
additionalProperties: false
required:
[
lotNumber,
cataloguePosition,
biddingOpens,
scheduledCloses,
reportedClosedAt,
]
description: Immutable historical listing-owned Auction and lot facts. Their presence has no separate meaning. They never expose a source Auction key or shared Auction metadata.
properties:
auctionId:
type: string
description: Resolved Aura Auction TypeID. Omitted when no resolved membership is present.
lotNumber:
type: string
nullable: true
description: Optional source-assigned lot label.
cataloguePosition:
type: integer
format: int64
minimum: 1
maximum: 4294967295
nullable: true
description: Optional one-based source catalogue position.
biddingOpens:
type: string
format: date-time
nullable: true
scheduledCloses:
type: string
format: date-time
nullable: true
reportedClosedAt:
type: string
format: date-time
nullable: true
ProductListingAuctionTimesData:
type: object
additionalProperties: false
description: Omit each leaf to preserve it; send null to clear it; values are RFC3339 instants.
properties:
biddingOpens: { type: string, format: date-time, nullable: true }
scheduledCloses: { type: string, format: date-time, nullable: true }
reportedClosedAt: { type: string, format: date-time, nullable: true }
PriceEstimateData:
type: object
description: "Price estimate range for a product.
Contains optional minimum and maximum estimated prices.
"
properties:
min:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
description: Optional minimum estimated price for the product
max:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
description: Optional maximum estimated price for the product
PricingData:
type: object
description: "Complete pricing information for a product.
Contains both the offer price and optional price estimates.
"
properties:
offer:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
description: "The actual offer or asking price for the product.
This is the price at which the product is currently being sold.
"
estimate:
allOf:
- $ref: "#/components/schemas/PriceEstimateData"
nullable: true
description: "Optional price estimate range.
Common for auction items where an estimated value range is provided.
"
ProductListingImageData:
type: object
description: Product image after viewer-specific presentation.
required:
- url
properties:
url:
type: string
format: uri
nullable: true
description: URL to the product image, or `null` when it is not shown to this viewer.
example: https://my-listing-source.com/images/product-1.jpg
ContentPolicyData:
oneOf:
- type: object
required:
- decision
properties:
decision:
type: string
enum:
- ALLOWED
- type: object
required:
- decision
- category
properties:
decision:
type: string
enum:
- REQUIRES_CONSENT
category:
type: string
enum:
- NAZI_GERMANY
description: Listing-level content decision. This schema is used only when the listing has an assessment.
SortProductListingFieldData:
type: string
enum:
- score
- updated
- created
description: "Fields available for sorting:
- score: Sort by relevance score (default, only available when searching with text query)
- updated: Sort by last updated timestamp
- created: Sort by creation timestamp
"
default: score
example: updated
ProductListingHistoryEntryTypeData:
type: string
enum:
- PRODUCT_LISTING_DISCOVERED
- PRODUCT_LISTING_CHANGED
description: Canonical ProductListing domain-history entry type.
example: PRODUCT_LISTING_CHANGED
ProductListingHistoryPayloadData:
oneOf:
- $ref: "#/components/schemas/ProductListingDiscoveryHistoryPayloadData"
- $ref: "#/components/schemas/ProductListingChangedHistoryPayloadData"
description: Immutable semantic history payload. It never contains image URLs or enrichment data.
ProductListingDiscoveryHistoryPayloadData:
type: object
required:
- listingSourceId
- sourceListingId
- pricing
- availability
- url
- imageCount
- auction
properties:
listingSourceId:
type: string
sourceListingId:
type: string
title:
description: Normalized discovery title, with legacy constructor trailing whitespace presented trimmed without rewriting the stored event.
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
description:
$ref: "#/components/schemas/LocalizedTextData"
pricing:
$ref: "#/components/schemas/ProductListingHistoryPricingData"
availability:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
url:
type: string
format: uri
imageCount:
type: integer
format: int64
minimum: 0
auction:
allOf:
- $ref: "#/components/schemas/ProductListingAuctionFactsData"
nullable: true
ProductListingChangedHistoryPayloadData:
type: object
required:
- changes
properties:
changes:
type: array
minItems: 1
description: "Deterministic semantic-change order: main price, minimum estimate, maximum estimate, availability, URL, images, auction, lifecycle, sale observation."
items:
$ref: "#/components/schemas/ProductListingHistoryChangeData"
ProductListingHistoryChangeData:
oneOf:
- $ref: "#/components/schemas/ProductListingMainPriceHistoryChangeData"
- $ref: "#/components/schemas/ProductListingPriceHistoryChangeData"
- $ref: "#/components/schemas/ProductListingAvailabilityHistoryChangeData"
- $ref: "#/components/schemas/ProductListingUrlHistoryChangeData"
- $ref: "#/components/schemas/ProductListingImagesHistoryChangeData"
- $ref: "#/components/schemas/ProductListingAuctionHistoryChangeData"
- $ref: "#/components/schemas/ProductListingWithdrawalHistoryChangeData"
- $ref: "#/components/schemas/ProductListingRestorationHistoryChangeData"
- $ref: "#/components/schemas/ProductListingSaleObservationHistoryChangeData"
description: Typed semantic change.
ProductListingMainPriceHistoryChangeData:
type: object
required:
- type
- previous
- current
properties:
type:
type: string
enum:
- MAIN_PRICE_CHANGED
previous:
allOf:
- $ref: "#/components/schemas/ProductListingHistoryMainPriceData"
nullable: true
current:
allOf:
- $ref: "#/components/schemas/ProductListingHistoryMainPriceData"
nullable: true
ProductListingPriceHistoryChangeData:
type: object
required:
- type
- previous
- current
properties:
type:
type: string
enum:
- MINIMUM_ESTIMATE_CHANGED
- MAXIMUM_ESTIMATE_CHANGED
previous:
allOf:
- $ref: "#/components/schemas/ProductListingHistoryEstimateData"
nullable: true
current:
allOf:
- $ref: "#/components/schemas/ProductListingHistoryEstimateData"
nullable: true
ProductListingAvailabilityHistoryChangeData:
type: object
required:
- type
- previous
- current
properties:
type:
type: string
enum:
- AVAILABILITY_CHANGED
previous:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
current:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
ProductListingUrlHistoryChangeData:
type: object
required:
- type
- previous
- current
properties:
type:
type: string
enum:
- URL_CHANGED
previous:
type: string
format: uri
current:
type: string
format: uri
ProductListingImagesHistoryChangeData:
type: object
required:
- type
- previousCount
- currentCount
properties:
type:
type: string
enum:
- IMAGES_CHANGED
previousCount:
type: integer
format: int64
minimum: 0
currentCount:
type: integer
format: int64
minimum: 0
ProductListingAuctionHistoryChangeData:
type: object
required:
- type
- previous
- current
properties:
type:
type: string
enum:
- AUCTION_CHANGED
previous:
allOf:
- $ref: "#/components/schemas/ProductListingAuctionFactsData"
nullable: true
current:
allOf:
- $ref: "#/components/schemas/ProductListingAuctionFactsData"
nullable: true
ProductListingWithdrawalHistoryChangeData:
type: object
required:
- type
- previousAvailability
properties:
type:
type: string
enum:
- WITHDRAWN
previousAvailability:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
ProductListingRestorationHistoryChangeData:
type: object
required:
- type
properties:
type:
type: string
enum:
- RESTORED
ProductListingSaleObservationHistoryChangeData:
type: object
required:
- type
- observation
properties:
type:
type: string
enum:
- SALE_OBSERVED
- SALE_OBSERVATION_RETRACTED
observation:
type: object
required:
- observedAt
- fxRateId
properties:
observedAt:
type: string
format: date-time
fxRateId:
type: string
ApiError:
type: object
description: Standard error response format (RFC 9457)
required:
- status
- title
- error
properties:
status:
type: integer
description: HTTP status code
example: 400
title:
type: string
description: HTTP status code in human-readable form
example: Bad Request
error:
type: string
description: Error code identifier
example: BAD_PARAMETER
source:
$ref: "#/components/schemas/ApiErrorSource"
detail:
type: string
description: Human-readable error message
example: "Expected any of: 'true' or 'false'. Got: 'invalid'"
ApiErrorSource:
type: object
description: Information about the source of the error
required:
- field
- type
properties:
field:
type: string
description: Name of the field that caused the error
example: listingSourceId
type:
type: string
enum:
- QUERY
- PATH
- HEADER
- BODY
description: Type of parameter that caused the error
example: PATH
ProductListingSearchData:
type: object
description: ProductListing search criteria used by saved search filters.
properties:
language:
$ref: "#/components/schemas/LanguageData"
currency:
$ref: "#/components/schemas/CurrencyData"
productQuery:
type: array
items: &id001
type: string
minLength: 1
enhancedSearchDescription:
type: string
minLength: 1
maxLength: 1000
nullable: true
excludeProductId:
type: array
items:
type: string
uniqueItems: true
description: ProductListing IDs to exclude.
listingSourceId:
type: array
items: &id002
type: string
uniqueItems: true
description: ListingSource IDs to include.
excludeListingSourceId:
type: array
items: &id003
type: string
uniqueItems: true
description: ListingSource IDs to exclude.
nullable: true
auctionId:
type: array
items:
type: string
uniqueItems: true
maxItems: 100
nullable: true
description: Exact resolved Auction membership IDs. Omit to preserve; `null` clears.
price:
allOf: &id004
- $ref: "#/components/schemas/RangeQueryUInt64"
nullable: true
availability:
type: array
items: &id005
$ref: "#/components/schemas/ListingAvailabilityData"
uniqueItems: true
nullable: true
orderability:
type: array
items: &id006
$ref: "#/components/schemas/ListingOrderabilityData"
uniqueItems: true
nullable: true
includeUnspecifiedAvailability:
type: boolean
nullable: true
created:
allOf: &id007
- $ref: "#/components/schemas/RangeQueryDateTime"
nullable: true
updated:
allOf: &id008
- $ref: "#/components/schemas/RangeQueryDateTime"
nullable: true
lotBiddingOpens:
allOf: &id009
- $ref: "#/components/schemas/RangeQueryDateTime"
nullable: true
lotScheduledCloses:
allOf: &id010
- $ref: "#/components/schemas/RangeQueryDateTime"
nullable: true
geography:
$ref: '#/components/schemas/GeographicSearchData'
PostUserSearchFilterData:
type: object
description: Request body for creating a new search filter
required:
- name
- search
properties:
name:
type: string
description: User-defined name for the search filter (max 255 characters, will be truncated if longer)
maxLength: 255
example: My Tech Store Search
search:
$ref: "#/components/schemas/ProductListingSearchData"
PatchUserSearchFilterData:
type: object
description: "Partial search filter update data.
All fields are optional and only provided fields will be updated.
Can update the search filter name, notifications preference, activation state, and/or the search filter criteria.
"
properties:
name:
type: string
description: User-defined name for the search filter (max 255 characters, will be truncated if longer)
maxLength: 255
nullable: true
example: Updated Filter Name
notifications:
type: boolean
nullable: true
description:
"Whether to enable or disable email notifications for new product-listings matching this search filter.
When `true`, the user will be notified when a new product matches this filter.
When `false`, no notifications are sent for this filter.
Omit to leave unchanged.
"
example: true
state:
allOf:
- $ref: "#/components/schemas/PatchResourceStateData"
nullable: true
description:
"Optional activation state update for this saved search filter.
`ACTIVE` reactivates the filter if the current user tier still permits the configured search features and quota.
`INACTIVE_BY_USER` manually disables the filter.
Omit to leave the current state unchanged.
"
search:
allOf:
- $ref: "#/components/schemas/PatchProductListingSearchData"
nullable: true
description: Partial search filter criteria to update
PatchUserSearchFilterMatchData:
type: object
description: "Partial update payload for a saved-search product match.
Omitting `feedback` leaves the stored match feedback unchanged.
"
properties:
feedback:
type: boolean
nullable: true
description: "Optional relevance feedback for the matched product.
`true` marks the product as relevant to the saved search filter, `false` marks it as not relevant.
"
example: true
PatchProductListingSearchData:
type: object
description:
Partial ProductListing search criteria. Omitted fields are unchanged. `enhancedSearchDescription`, `auctionId`, price,
date ranges, and the availability query may be cleared with `null`; availability, orderability, and includeUnspecifiedAvailability`
must be supplied together or all be `null`.
properties:
language:
$ref: "#/components/schemas/LanguageData"
nullable: true
currency:
$ref: "#/components/schemas/CurrencyData"
nullable: true
productQuery:
type: array
items: *id001
nullable: true
enhancedSearchDescription:
type: string
minLength: 1
maxLength: 1000
nullable: true
listingSourceId:
type: array
items: *id002
uniqueItems: true
description: ListingSource IDs to include.
nullable: true
excludeListingSourceId:
type: array
items: *id003
uniqueItems: true
description: ListingSource IDs to exclude.
auctionId:
type: array
items:
type: string
uniqueItems: true
maxItems: 100
description: Exact resolved Auction membership IDs. Values use strict `auc_` TypeIDs and OR together.
price:
allOf: *id004
nullable: true
availability:
type: array
items: *id005
uniqueItems: true
nullable: true
orderability:
type: array
items: *id006
uniqueItems: true
nullable: true
includeUnspecifiedAvailability:
type: boolean
nullable: true
created:
allOf: *id007
nullable: true
updated:
allOf: *id008
nullable: true
lotBiddingOpens:
allOf: *id009
nullable: true
lotScheduledCloses:
allOf: *id010
nullable: true
geography:
nullable: true
allOf: [{$ref: '#/components/schemas/GeographicSearchData'}]
description: Omitted leaves the private snapshot unchanged; null clears; an object replaces the complete geography predicate.
UserSearchFilterData:
type: object
description: Complete user search filter with metadata
required:
- userId
- userSearchFilterId
- name
- notifications
- state
- search
- createdBy
- updatedBy
- created
- updated
properties:
userId:
type: string
description: Unique identifier of the user who owns this search filter
example: usr_5pvhvpxyhve6ts31n9x8c2y513
userSearchFilterId:
type: string
description: Unique identifier for this search filter
example: sf_4hyqf0gyxveazss7nby5hve5x2
name:
type: string
description: User-defined name for the search filter
example: My Tech Store Search
notifications:
type: boolean
description:
"Whether notifications are enabled for this search filter.
When `true`, the user will be notified when a new product matches this filter.
When `false`, no notifications are sent for this filter.
Defaults to `true` for newly created filters.
"
example: true
state:
$ref: "#/components/schemas/ResourceStateData"
search:
$ref: "#/components/schemas/ProductListingSearchData"
createdBy:
$ref: "#/components/schemas/ActorData"
updatedBy:
$ref: "#/components/schemas/ActorData"
created:
type: string
format: date-time
description: When the search filter was created (RFC3339 format)
example: "2024-01-01T10:00:00Z"
updated:
type: string
format: date-time
description: When the search filter was last updated (RFC3339 format)
example: "2024-01-01T12:00:00Z"
ResourceStateData:
type: string
description:
"Activation state of a stored user-owned resource such as a saved search filter.
`ACTIVE` resources are eligible for their normal runtime behavior.
`INACTIVE_BY_USER` resources were explicitly deactivated by the user.
`INACTIVE_BY_RESTRICTED_PLAN` resources remain stored but are inactive because the user's current tier no longer
allows them to stay active.
"
enum:
- ACTIVE
- INACTIVE_BY_USER
- INACTIVE_BY_RESTRICTED_PLAN
example: ACTIVE
PatchResourceStateData:
type: string
description:
"Client-settable activation state for resources that support manual activation toggles.
Clients may reactivate a resource with `ACTIVE` or manually disable it with `INACTIVE_BY_USER`.
`INACTIVE_BY_RESTRICTED_PLAN` is managed internally by the backend and is never accepted from clients.
"
enum:
- ACTIVE
- INACTIVE_BY_USER
example: INACTIVE_BY_USER
SearchFilterProductMatchData:
type: object
description: Persisted match record for one of a user's saved search filters.
required:
- userId
- userSearchFilterId
- productListingId
- originEventId
- created
- updated
properties:
userId:
type: string
description: Unique identifier of the user who owns the matched search filter.
example: usr_5pvhvpxyhve6ts31n9x8c2y513
userSearchFilterId:
type: string
description: Unique identifier of the saved search filter that matched the product.
example: sf_4hyqf0gyxveazss7nby5hve5x2
userSearchFilterName:
type: string
description: Saved-search name captured with the match, when available.
example: Golden Accessories
productListingId:
type: string
description: Unique internal identifier of the matched product.
example: pl_6zydvb8xqqfcntt760grgm41t4
originEventId:
type: string
description: Product event that produced this match.
example: evt_08nrsmex2je2dvsyh01v2kh78a
feedback:
type: boolean
description: Optional feedback recorded by the user for this saved-search match.
example: true
created:
type: string
format: date-time
description: When the search-filter product match was originally created (RFC3339 format).
example: "2024-01-01T10:00:00Z"
updated:
type: string
format: date-time
description: When the search-filter product match was last updated (RFC3339 format).
example: "2024-01-01T12:30:00Z"
RangeQueryUInt64:
type: object
description:
Range query for numeric values in minor currency units for the selected indexed currency; no request-time
conversion occurs
properties:
min:
type: integer
minimum: 0
description: Minimum value (inclusive)
example: 1000
max:
type: integer
minimum: 0
description: Maximum value (inclusive)
example: 5000
RangeQueryDateTime:
type: object
description: Range query for date and time values
properties:
min:
type: string
format: date-time
description: Minimum date and time (inclusive, RFC3339 format)
example: "2024-01-01T00:00:00Z"
max:
type: string
format: date-time
description: Maximum date and time (inclusive, RFC3339 format)
example: "2024-12-31T23:59:59Z"
UserSearchFilterCollectionData:
type: object
description: Paginated collection of user search filters with flattened pagination
required:
- items
- from
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/UserSearchFilterData"
description: Array of search filters in the current page
from:
type: integer
minimum: 0
description: Number of product-listings skipped (offset)
example: 0
size:
type: integer
minimum: 0
description: Number of search filters returned in the current page.
example: 21
total:
type: integer
minimum: 0
description: Total number of product-listings matching the query
nullable: true
example: 127
AccessTokenScopeData:
type: string
enum:
- auctions:read
- auctions:write
- listing-sources:read
- parties:read
- parties:write
- partnership-applications:read
- partnership-applications:write
- partnerships:read
- partnerships:write
- admin-overview:read
- search-filters:read
- notifications:read
- notifications:write
- product-listings:write
- listing-sources:write
- users:read
- users:write
- access-tokens:read
- access-tokens:write
- search-filters:write
- watchlist:read
- watchlist:write
description: "Aura Historia access-token and OAuth scope string.
The value is one of the capabilities supported by the canonical access-token and OAuth flows.
"
example: access-tokens:read
AccessTokenTypeData:
type: string
enum:
- BEARER
description: Token type returned for Aura Historia access tokens.
example: BEARER
AdminAccessTokenCollectionData:
type: object
description:
"Cursor-paginated, secret-free access-token metadata for an administrator's explicit target user.
`searchAfter` is a `[created RFC3339 timestamp, AccessToken ID]` cursor and is omitted
when the current page is terminal. The cursor timestamp is not returned as item metadata.
This schema intentionally has no raw token, masked token, short-token, or token-hash property.
"
required:
- items
- size
properties:
items:
type: array
description: Access-token metadata returned for the target user, including expired and current tokens.
items:
$ref: "#/components/schemas/AdminAccessTokenData"
size:
type: integer
format: int64
minimum: 0
maximum: 100
description: Number of items returned in the current page.
example: 21
searchAfter:
type: array
minItems: 2
maxItems: 2
items:
type: string
description: "`[created RFC3339 timestamp, AccessToken ID]` cursor for the next page, omitted when no more results are available."
nullable: true
example:
- "2026-09-04T12:00:00Z"
- at_4ck23tcv0meqqrbyjaka24ra6g
AdminAccessTokenData:
type: object
description:
"Secret-free Aura Historia access-token metadata returned by the admin target-user listing.
The representation contains no raw token, masked token, short-token, or token-hash value.
`expires` is omitted when the token has no expiration and is returned for both expired and current tokens.
"
required:
- userId
- accessTokenId
- name
- scopes
- origin
properties:
userId:
type: string
description: Explicit target user who owns the access token.
example: usr_5pvhvpxyhve6ts31n9x8c2y513
accessTokenId:
type: string
description: Unique identifier of the access token.
example: at_4ck23tcv0meqqrbyjaka24ra6g
name:
type: string
maxLength: 128
description: User-defined display name of the access token.
example: Incident review token
scopes:
type: array
uniqueItems: true
description: Granted access-token scopes.
items:
$ref: "#/components/schemas/AccessTokenScopeData"
example:
- users:read
origin:
type: string
description: Origin recorded by the canonical access-token model.
example: User
expires:
type: string
format: date-time
description: Optional RFC3339 expiration timestamp; expired and current tokens are both listed.
nullable: true
example: "2026-09-30T00:00:00Z"
OwnAccessTokenData:
type: object
description:
"Secret-free metadata for an access token owned by the authenticated user.
List, get, and update responses omit the bearer token entirely; the plaintext is only returned by
the create operation.
"
required:
- userId
- accessTokenId
- name
- scopes
- origin
properties:
userId:
type: string
description: User who owns the access token.
example: usr_5pvhvpxyhve6ts31n9x8c2y513
accessTokenId:
type: string
description: Unique identifier of the access token.
example: at_4ck23tcv0meqqrbyjaka24ra6g
name:
type: string
maxLength: 128
description: User-defined display name of the access token.
example: Partner product sync
scopes:
type: array
items:
$ref: "#/components/schemas/AccessTokenScopeData"
uniqueItems: true
description: Granted access-token scopes. An empty scope set is returned as an empty array.
example:
- product-listings:write
origin:
type: string
description: Origin recorded by the access-token model.
example: User
expires:
type: string
format: date-time
description: Optional RFC3339 expiration timestamp; omitted when the token does not expire and returned for expired and current tokens.
example: "2026-06-30T00:00:00Z"
CreatedAccessTokenData:
type: object
description:
"Minimal access-token creation result. The plaintext bearer token is returned only once.
Subsequent list, get, and update operations return secret-free metadata without any token value.
"
required:
- userId
- accessTokenId
- accessToken
properties:
userId:
type: string
description: User who owns the access token.
example: usr_5pvhvpxyhve6ts31n9x8c2y513
accessTokenId:
type: string
description: Unique identifier of the created access token.
example: at_4ck23tcv0meqqrbyjaka24ra6g
accessToken:
type: string
description: Plaintext bearer token. Store it securely; it cannot be retrieved again.
example: aurahistoria_abcdefghijk_abcdefghijklmnopqrstuvwxyz1234567
PostAccessTokenData:
type: object
description:
"Request body for creating an Aura Historia access token. `scopes` is required, including
when the requested scope set is empty. `expires` is optional.
"
required:
- name
- scopes
properties:
name:
type: string
maxLength: 128
description: User-defined display name of the new access token.
example: Partner product sync
scopes:
type: array
items:
$ref: "#/components/schemas/AccessTokenScopeData"
uniqueItems: true
description: Required scopes granted to the access token. Send an empty array for no scopes.
example:
- product-listings:write
expires:
type: string
format: date-time
nullable: true
description: Optional RFC3339 expiration timestamp.
example: "2026-06-30T00:00:00Z"
PatchAccessTokenData:
type: object
description: "Request body for updating access-token metadata.
Omitted fields remain unchanged. `expires: null` clears the expiry; `name` and `scopes`
reject null, and `scopes: []` replaces the scope set with an empty set.
"
required:
- accessTokenId
properties:
accessTokenId:
type: string
description: Unique identifier of the access token to update.
example: at_4ck23tcv0meqqrbyjaka24ra6g
name:
type: string
maxLength: 128
description: Omit to leave unchanged. Null is invalid.
example: Renamed partner sync token
scopes:
type: array
items:
$ref: "#/components/schemas/AccessTokenScopeData"
uniqueItems: true
description: Omit to leave unchanged. Send `[]` to empty the set; null is invalid.
example:
- product-listings:write
expires:
type: string
format: date-time
nullable: true
description: Omit to leave unchanged. Send null to clear the expiration timestamp.
example: "2026-07-31T00:00:00Z"
OAuthClientConsentMetadataData:
type: object
additionalProperties: false
description:
"Minimal secret-free OAuth client metadata returned to an authenticated user before consent.
`client_id`, URLs, redirect URIs, and allowed scopes come from the persisted registration. Redirect URIs are
returned as registered and must not be treated as a wildcard allowlist. `scope` contains allowed scopes only,
not scopes the user has granted; an empty set is `[]`. This schema intentionally excludes client secrets,
secret hashes or short-token material, bearer tokens, authorization codes, verifiers, timestamps, and audit data.
"
required:
- client_id
- client_name
- tos_uri
- policy_uri
- client_uri
- logo_uri
- redirect_uris
- scope
properties:
client_id:
type: string
description: Canonical OAuthClient ID (`oc_` TypeID).
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_name:
type: string
description: Display name stored for the OAuth client.
example: Aura Historia WooCommerce
tos_uri:
type: string
format: uri
description: Terms-of-service URL stored for the OAuth client.
example: https://integration.example/terms
policy_uri:
type: string
format: uri
description: Privacy-policy URL stored for the OAuth client.
example: https://integration.example/privacy
client_uri:
type: string
format: uri
description: Homepage URL stored for the OAuth client.
example: https://integration.example
logo_uri:
type: string
format: uri
description: Logo URL stored for the OAuth client.
example: https://integration.example/logo.png
redirect_uris:
type: array
uniqueItems: true
description: Exact registered redirect URLs, including their registered query strings and other URI components.
items:
type: string
format: uri
example:
- https://stage.aura-historia.com/api/oauth/client/redirect-broker/woocommerce
scope:
type: array
uniqueItems: true
description: Allowed OAuth scopes; this does not mean that the user has granted them. Empty registrations return `[]`.
items:
$ref: "#/components/schemas/AccessTokenScopeData"
example:
- product-listings:write
OAuthClientMetadataRequestData:
type: object
description: "Request body for creating OAuth client metadata.
`redirect_uris` must contain at least one HTTPS redirect URI.
"
required:
- client_name
- tos_uri
- policy_uri
- client_uri
- logo_uri
- redirect_uris
properties:
client_name:
type: string
description: Display name of the OAuth client.
example: Acceptance OAuth client
tos_uri:
type: string
format: uri
description: HTTPS URL of the OAuth client's terms-of-service document.
example: https://client.example/tos
policy_uri:
type: string
format: uri
description: HTTPS URL of the OAuth client's privacy policy document.
example: https://client.example/policy
client_uri:
type: string
format: uri
description: HTTPS URL of the OAuth client's homepage or product site.
example: https://client.example
logo_uri:
type: string
format: uri
description: HTTPS URL of the OAuth client's logo image.
example: https://client.example/logo.png
redirect_uris:
type: array
minItems: 1
uniqueItems: true
description: Registered HTTPS redirect URIs for the OAuth client.
items:
type: string
format: uri
example:
- https://client.example/callback
scope:
type: array
uniqueItems: true
description: Optional allowed scopes for tokens issued to this OAuth client.
items:
$ref: "#/components/schemas/AccessTokenScopeData"
example:
- product-listings:write
OAuthClientMetadataPatchData:
type: object
description:
"Request body for updating OAuth client metadata. Omitted properties remain unchanged;
every explicit null is invalid because metadata values are non-nullable.
"
properties:
client_name:
type: string
description: Optional replacement display name for the OAuth client.
example: Updated acceptance OAuth client
tos_uri:
type: string
format: uri
description: Optional replacement terms-of-service document URL for the OAuth client.
example: https://client.example/updated-tos
policy_uri:
type: string
format: uri
description: Optional replacement privacy-policy document URL for the OAuth client.
example: https://client.example/updated-policy
client_uri:
type: string
format: uri
description: Optional replacement homepage or product-site URL for the OAuth client.
example: https://updated-client.example
logo_uri:
type: string
format: uri
description: Optional replacement logo image URL for the OAuth client.
example: https://updated-client.example/logo.png
redirect_uris:
type: array
minItems: 1
uniqueItems: true
description: Optional replacement set of registered HTTPS redirect URIs.
items:
type: string
format: uri
example:
- https://client.example/updated
scope:
type: array
uniqueItems: true
description: Omit to leave unchanged. Send `[]` to replace with an empty set; null is invalid.
items:
$ref: "#/components/schemas/AccessTokenScopeData"
example:
- access-tokens:read
OAuthClientMetadataResponseData:
type: object
description: "OAuth client metadata create response.
`client_secret` contains the plaintext secret only in the create response.
Admin list, detail, and update responses use `OAuthClientAdminData` and omit
`client_secret` entirely.
"
required:
- client_id
- client_secret
- client_name
- tos_uri
- policy_uri
- client_uri
- logo_uri
- redirect_uris
- scope
- client_id_issued_at
properties:
client_id:
type: string
description: Canonical OAuthClient ID.
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_secret:
type: string
description:
"Plaintext OAuth client secret returned only once by the create response.
Admin list, detail, and update responses omit this property entirely.
"
example: aurahistoria_oauth_client_secret_abcdefghijk_abcdefghijklmnopqrstuvwxyz1234567
client_name:
type: string
description: Display name of the OAuth client.
example: Acceptance OAuth client
tos_uri:
type: string
format: uri
description: Terms-of-service document URL registered for the OAuth client.
example: https://client.example/tos
policy_uri:
type: string
format: uri
description: Privacy-policy document URL registered for the OAuth client.
example: https://client.example/policy
client_uri:
type: string
format: uri
description: Homepage or product-site URL registered for the OAuth client.
example: https://client.example
logo_uri:
type: string
format: uri
description: Logo image URL registered for the OAuth client.
example: https://client.example/logo.png
redirect_uris:
type: array
uniqueItems: true
description: Registered redirect URIs for the OAuth client.
items:
type: string
format: uri
example:
- https://client.example/callback
scope:
type: array
uniqueItems: true
description: Allowed scopes for tokens issued to this OAuth client.
items:
$ref: "#/components/schemas/AccessTokenScopeData"
example:
- product-listings:write
client_id_issued_at:
type: integer
format: int64
description: Unix timestamp (seconds) when the OAuth client was created and its client ID was issued.
example: 1748539200
OAuthClientAdminCollectionData:
type: object
description:
"Cursor-paginated OAuth client summaries for the administrator collection endpoint.
`searchAfter` is a `[created RFC3339 timestamp, OAuthClient ID]` cursor and is omitted
when the current page is terminal. The collection and its items never contain client
secret plaintext, secret hashes, or masked secret values.
"
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/OAuthClientAdminData"
description: OAuth client summaries returned in the current page.
size:
type: integer
format: int64
minimum: 0
maximum: 100
description: Number of items returned in the current page.
example: 21
searchAfter:
type: array
minItems: 2
maxItems: 2
items:
type: string
description: "`[created RFC3339 timestamp, OAuthClient ID]` cursor for the next page, omitted when no more results are available."
nullable: true
example:
- "2026-09-04T12:00:00Z"
- oc_7b0gwc1x49e0mvbt3tfexfqgb5
total:
type: integer
format: int64
minimum: 0
description: Total matching OAuth clients when provided by the reader; omitted otherwise.
nullable: true
example: 42
OAuthClientAdminData:
type: object
description:
"Secret-free OAuth client metadata returned by the admin OAuth client collection,
detail, and update endpoints under `/api/v1/admin/oauth-clients`.
This schema intentionally has no `client_secret` property.
"
required:
- client_id
- client_name
- tos_uri
- policy_uri
- client_uri
- logo_uri
- redirect_uris
- scope
- client_id_issued_at
properties:
client_id:
type: string
description: Canonical OAuthClient ID.
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
client_name:
type: string
description: Display name of the OAuth client.
example: Dashboard integration
tos_uri:
type: string
format: uri
description: Terms-of-service document URL registered for the OAuth client.
example: https://client.example/tos
policy_uri:
type: string
format: uri
description: Privacy-policy document URL registered for the OAuth client.
example: https://client.example/policy
client_uri:
type: string
format: uri
description: Homepage or product-site URL registered for the OAuth client.
example: https://client.example
logo_uri:
type: string
format: uri
description: Logo image URL registered for the OAuth client.
example: https://client.example/logo.png
redirect_uris:
type: array
uniqueItems: true
description: Registered redirect URIs for the OAuth client.
items:
type: string
format: uri
example:
- https://client.example/callback
scope:
type: array
uniqueItems: true
description: Allowed scopes for tokens issued to this OAuth client.
items:
$ref: "#/components/schemas/AccessTokenScopeData"
example:
- access-tokens:read
client_id_issued_at:
type: integer
format: int64
description: Unix timestamp (seconds) when the OAuth client was created and its client ID was issued.
example: 1748539200
OAuthTokenResponseData:
type: object
description: "Token response returned by `POST /api/v1/oauth/token` and
`GET /api/v1/oauth/tokens/by-third-party-code/{thirdPartyCode}`.
The `access_token` is an Aura Historia bearer access token. `expires_in` is omitted
(`null`) for non-expiring tokens. `third_party_exchange_code` is only present on the
direct token exchange response.
"
required:
- access_token
- token_type
- scope
properties:
access_token:
type: string
description: The issued Aura Historia access token (plaintext bearer value).
example: aurahistoria_abcdefghijk_verylongtokenvalue
token_type:
$ref: "#/components/schemas/AccessTokenTypeData"
expires_in:
type: integer
format: int64
minimum: 0
nullable: true
description: Seconds until the access token expires. `null` when the token does not expire.
example: null
scope:
type: string
description: Space-separated list of scopes granted to the access token.
example: product-listings:write
third_party_exchange_code:
type: string
format: uuid
description:
"Optional one-time exchange code returned by `POST /api/v1/oauth/token`.
It can be redeemed once via `GET /api/v1/oauth/tokens/by-third-party-code/{thirdPartyCode}`
within 60 seconds to obtain the same access token.
"
example: 01970f22-2bf0-7000-8000-000000000099
OAuthIntrospectionResponseData:
type: object
description:
"Introspection response returned by `POST /api/v1/oauth/introspect` (RFC 7662).
When `active` is `false` all other fields are omitted.
When `active` is `true` the available token metadata is populated.
"
required:
- active
properties:
active:
type: boolean
description: Whether the token is currently active (not expired, not revoked, and known to this server).
example: true
scope:
type: string
description: Space-separated list of scopes granted to the token. Present only when `active` is `true`.
example: product-listings:write
client_id:
type: string
description:
OAuthClient ID that issued the token. Present only when `active` is `true` and the
token was issued via the OAuth flow.
example: oc_7b0gwc1x49e0mvbt3tfexfqgb5
sub:
type: string
description: Subject — the Aura Historia user ID who authorized the token. Present only when `active` is `true`.
example: usr_4hzreqwxgvef69j056bszwwm17
token_type:
type: string
description: Token type. Always `"Bearer"` when `active` is `true`.
example: Bearer
exp:
type: integer
format: int64
description:
Unix timestamp (seconds) when the token expires. Present only when `active` is `true` and the token
has an expiry.
example: 1780000000
iat:
type: integer
format: int64
description:
Unix timestamp (seconds) when the token was issued. Present only when `active` is `true` and the issue
time is known.
example: 1748400000
PostWatchlistData:
type: object
description: Request body for creating a watchlist entry.
required:
- productListingId
properties:
productListingId:
type: string
description: Canonical identifier of the product to add to the watchlist.
example: pl_5xdb465tg1enarx2knf04mxbxj
notifications:
type: boolean
description: Whether notifications are enabled for this entry. Defaults to `true`.
default: true
example: true
WatchlistEntryData:
type: object
description: A user's watchlist entry.
required:
- userId
- productListingId
- notifications
- state
properties:
userId:
type: string
description: Identifier of the user who owns the entry.
example: usr_5pvhvpxyhve6ts31n9x8c2y513
productListingId:
type: string
description: Canonical identifier of the watched product.
example: pl_5xdb465tg1enarx2knf04mxbxj
notifications:
type: boolean
description: Whether notifications are enabled for this entry.
example: true
state:
$ref: "#/components/schemas/ResourceStateData"
created:
type: string
format: date-time
description: When the entry was created, when available.
example: "2026-08-06T12:00:00Z"
updated:
type: string
format: date-time
description: When the entry was last updated, when available.
example: "2026-08-06T12:00:00Z"
WatchlistProductPatch:
type: object
description: Patch object for updating watchlist product settings
properties:
notifications:
type: boolean
description: Whether to enable or disable notifications for this watchlist product
example: true
state:
allOf:
- $ref: "#/components/schemas/PatchResourceStateData"
nullable: true
description:
"Optional activation state update for this watchlist entry.
`ACTIVE` reactivates the entry if the user's current tier still has watchlist quota.
`INACTIVE_BY_USER` manually disables the entry.
Omit to leave the current state unchanged.
"
SortListingSourceFieldData:
type: string
enum:
- name
- slug
- created
- updated
description: "Fields available for sorting admin ListingSource-search results. ListingSource ID is always used as a deterministic tie-breaker."
example: name
SortPartyFieldData:
type: string
enum:
- name
- email
- phone
- created
- updated
description: "Fields available for sorting admin Party-search results. Party ID is always used as a deterministic tie-breaker; absent contact values sort last."
example: name
CreatePartyData:
type: object
description: Party name and optional contact information used to create an admin Party.
required:
- name
properties:
name:
type: string
maxLength: 255
description: Party name. Outer Unicode whitespace is trimmed; blank values and values over 255 UTF-8 bytes are rejected.
phone:
type: string
description: Optional Party phone number.
email:
type: string
format: email
description: Optional Party email address.
UpdatePartyData:
type: object
description: "Partial admin Party update. Omitted members remain unchanged; null clears only phone and email."
properties:
name:
type: string
maxLength: 255
description: "Replacement Party name. Outer Unicode whitespace is trimmed; blank values, values over 255 UTF-8 bytes, and null are rejected."
phone:
type: string
nullable: true
description: "Replacement Party phone number; null clears it."
email:
type: string
format: email
nullable: true
description: "Replacement Party email address; null clears it."
PartyData:
type: object
description: Party representation returned after admin creation, update, and detail routes.
required:
- partyId
- partySlugId
- name
- contact
- created
- updated
properties:
partyId:
type: string
description: Stable Party identifier.
partySlugId:
type: string
description: Immutable Party slug identifier.
name:
type: string
maxLength: 255
description: Party name.
contact:
$ref: "#/components/schemas/PartyContactData"
created:
type: string
format: date-time
description: When the Party was created.
updated:
type: string
format: date-time
description: When the Party was last updated.
PartyCollectionData:
type: object
description: "Cursor-paginated Party summaries for the admin search endpoint. `searchAfter` is a Party ID cursor and is omitted when the current page is terminal."
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/PartySummaryData"
description: Party summaries returned in the current page.
size:
type: integer
minimum: 0
maximum: 100
description: Number of items returned in the current page.
example: 21
searchAfter:
type: string
description: Party ID cursor for the next page, omitted when no more results are available.
example: pty_71m2jxjctefykb6crqka16yf6z
total:
type: integer
minimum: 0
description: Total matching Parties when provided by the reader; omitted otherwise.
example: 42
PartySummaryData:
type: object
description: Compact Party data returned by the administrator Party-search endpoint.
required:
- partyId
- partySlugId
- name
- contact
- created
- updated
properties:
partyId:
type: string
description: Stable Party identifier.
partySlugId:
type: string
description: Immutable Party slug identifier.
name:
type: string
maxLength: 255
description: Party name.
contact:
$ref: "#/components/schemas/PartyContactData"
created:
type: string
format: date-time
description: When the Party was created.
updated:
type: string
format: date-time
description: When the Party was last updated.
PartyContactData:
type: object
description: Optional Party contact summary. Absent contact members are omitted.
properties:
phone:
type: string
description: Party phone number, omitted when absent.
email:
type: string
format: email
description: Party email address, omitted when absent.
SortUserFieldData:
type: string
enum:
- name
- email
- firstName
- lastName
- tier
- role
- updated
- created
description: "Fields available for sorting admin user-search results:
- name: First name followed by last name
- email: User email address
- firstName: User first name
- lastName: User last name
- tier: User subscription tier
- role: User role
- updated: Last update timestamp
- created: Creation timestamp
Every sort uses user ID as a deterministic tie-breaker.
"
example: email
SearchFilterMatchProductCollectionData:
type: object
description: Cursor-paginated personalized ProductListing details for persisted search-filter matches.
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/PersonalizedProductListingDetailsData"
description: Persisted matches in ascending match-creation order.
size:
type: integer
minimum: 0
maximum: 100
description: Number of items returned in the current page.
example: 21
searchAfter:
type: array
minItems: 2
maxItems: 2
items:
type: string
description: >-
Next-page cursor, present only when another page is available. It contains `[RFC3339 persisted
match creation timestamp, canonical ProductListing ID]`; serialize the returned array as the
`searchAfter` query parameter for the next request.
example:
- "2026-08-05T12:30:00Z"
- pl_6zydvb8xqqfcntt760grgm41t4
total:
type: integer
minimum: 0
description: Total number of persisted matches, when available.
example: 127
UserCollectionData:
type: object
description:
"Cursor-paginated collection of users for the admin search endpoint.
Items are compact admin user summaries. `searchAfter` is a User ID cursor for
the next page and is omitted when the current page is terminal. The cursor must
be sent with the same filters and sort as the page that returned it.
"
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/AdminUserSummaryData"
description: Admin user summaries returned in the current page.
size:
type: integer
minimum: 0
maximum: 100
description: Number of items returned in the current page.
example: 21
searchAfter:
type: string
description: User ID cursor for the next page, omitted when more results are unavailable.
example: usr_681w9znhe8eawrhebxd1046d44
total:
type: integer
minimum: 0
description: Total matching users when the reader provides it; omitted otherwise.
example: 42
AdminUserSummaryData:
type: object
description: Compact user account data returned by the administrator user-search endpoint.
required:
- userId
- email
- tier
- role
properties:
userId:
type: string
description: Unique identifier for the user.
email:
type: string
format: email
description: User's email address.
firstName:
type: string
maxLength: 64
description: User's first name, omitted when absent.
lastName:
type: string
maxLength: 64
description: User's last name, omitted when absent.
tier:
$ref: "#/components/schemas/UserTierData"
role:
$ref: "#/components/schemas/UserRoleData"
stripeCustomerId:
type: string
description: Persisted Stripe customer identifier, omitted when absent.
OwnUserAccountData:
type: object
description:
User-owned account information for `/api/v1/me/account`. Role, tier, and Stripe customer ID are read-only
here.
required:
- userId
- email
- showUnassessedOrSensitiveContent
- marketingEmailConsent
- tier
- role
properties:
userId:
type: string
description: Unique identifier for the user.
email:
type: string
format: email
description: User's email address.
firstName:
type: string
maxLength: 64
nullable: true
lastName:
type: string
maxLength: 64
nullable: true
language:
allOf:
- $ref: "#/components/schemas/LanguageData"
nullable: true
currency:
allOf:
- $ref: "#/components/schemas/CurrencyData"
nullable: true
measurementUnit:
allOf:
- $ref: "#/components/schemas/MeasurementUnitData"
nullable: true
showUnassessedOrSensitiveContent:
type: boolean
description: Stored preference for showing unassessed or sensitive content.
marketingEmailConsent:
type: boolean
readOnly: true
description: Whether the current account email has an active grant for email marketing.
tier:
$ref: "#/components/schemas/UserTierData"
role:
$ref: "#/components/schemas/UserRoleData"
stripeCustomerId:
type: string
nullable: true
description: Persisted Stripe customer identifier, omitted when absent.
AdminUserAccountData:
allOf:
- $ref: "#/components/schemas/OwnUserAccountData"
- type: object
description: Admin user account view. Same read fields as own account; write permissions differ by endpoint.
SuspendUserData:
type: object
description: Required administrator-supplied explanation for suspending a user.
required:
- reason
properties:
reason:
type: string
minLength: 1
maxLength: 1000
description: Non-empty, non-whitespace explanation for the suspension. This value is emitted to structured operational logs; do not include tokens, passwords, credentials, or other secrets. Common credential markers are rejected.
example: Repeated policy violations
SuspendUserResponseData:
type: object
required:
- userId
- suspended
properties:
userId:
type: string
description: Identifier of the target user.
suspended:
type: boolean
description: Current suspension state; true after this operation, including an idempotent repeat.
example: true
UnsuspendUserResponseData:
type: object
required:
- userId
- suspended
properties:
userId:
type: string
description: Identifier of the target user.
suspended:
type: boolean
description: Current suspension state; false after this operation, including an idempotent repeat.
example: false
PatchAdminUserData:
type: object
description: "Partial admin-only user update payload.
All fields are optional. Omitted fields remain unchanged.
Only one logical change category may be sent per request: profile/preferences fields, `role`, or `tier`.
`marketingEmailConsent` is read-only and cannot be changed through this payload.
The canonical account email is read-only.
"
properties:
firstName:
type: string
maxLength: 64
nullable: true
description: New first name (truncated to 64 Unicode characters).
example: Ada
lastName:
type: string
maxLength: 64
nullable: true
description: New last name (truncated to 64 Unicode characters).
example: Lovelace
language:
allOf:
- $ref: "#/components/schemas/LanguageData"
nullable: true
description: New preferred language.
currency:
allOf:
- $ref: "#/components/schemas/CurrencyData"
nullable: true
description: New preferred currency.
measurementUnit:
allOf:
- $ref: "#/components/schemas/MeasurementUnitData"
nullable: true
description: New preferred measurement unit system.
showUnassessedOrSensitiveContent:
type: boolean
description:
Omit to leave unchanged. Send `true` to show unassessed or sensitive content; send `false` to hide
it. `null` is invalid.
example: true
tier:
allOf:
- $ref: "#/components/schemas/UserTierData"
description: Omit to leave unchanged. Null is invalid.
role:
allOf:
- $ref: "#/components/schemas/UserRoleData"
description: Omit to leave unchanged. Null is invalid.
PatchUserAccountData:
type: object
description: "Partial user account update data.
All fields are optional - only provided fields will be updated.
`marketingEmailConsent` is read-only and cannot be changed through this payload.
The canonical account email is read-only.
"
properties:
firstName:
type: string
maxLength: 64
nullable: true
description: New first name (truncated to 64 Unicode characters)
example: Jane
lastName:
type: string
maxLength: 64
nullable: true
description: New last name (truncated to 64 Unicode characters)
example: Smith
language:
allOf:
- $ref: "#/components/schemas/LanguageData"
nullable: true
description: New preferred language
currency:
allOf:
- $ref: "#/components/schemas/CurrencyData"
nullable: true
description: New preferred currency
measurementUnit:
allOf:
- $ref: "#/components/schemas/MeasurementUnitData"
nullable: true
description: New preferred measurement unit system
showUnassessedOrSensitiveContent:
type: boolean
description:
Omit to leave unchanged. Send `true` to show unassessed or sensitive content; send `false` to hide
it. `null` is invalid.
example: true
PostBillingCheckoutData:
type: object
description: Request body for creating a Stripe checkout session for a subscription purchase
required:
- plan
- cycle
properties:
plan:
$ref: "#/components/schemas/BillingPlanData"
cycle:
$ref: "#/components/schemas/BillingCycleData"
BillingPlanData:
type: string
description: Subscription plan that should be purchased through Stripe Checkout
enum:
- PRO
- ULTIMATE
example: PRO
BillingCycleData:
type: string
description: Billing interval that should be used for the subscription purchase
enum:
- MONTHLY
- YEARLY
example: MONTHLY
BillingSessionUrlData:
type: object
description: Hosted Stripe session URL returned by the billing endpoints
required:
- url
properties:
url:
type: string
format: uri
description: Hosted Stripe URL that the frontend should redirect the authenticated user to
example: https://checkout.stripe.com/c/pay/cs_test_123
PutNewsletterSubscriptionData:
type: object
description:
"Request body for requesting double opt-in confirmation for a newsletter subscription.
`email` is required; `firstName`, `lastName`, `language`, and `currency` are optional and may be omitted or set to `null`.
"
required:
- email
properties:
email:
type: string
format: email
description: Email address to subscribe to the newsletter
example: collector@example.com
firstName:
type: string
maxLength: 64
nullable: true
description: Optional first name to sync with the subscription
example: Ada
lastName:
type: string
maxLength: 64
nullable: true
description: Optional last name to sync with the subscription
example: Lovelace
language:
allOf:
- $ref: "#/components/schemas/LanguageData"
nullable: true
description: Optional preferred language to sync with the subscription
currency:
allOf:
- $ref: "#/components/schemas/CurrencyData"
nullable: true
description: Optional preferred currency to sync with the subscription
ConfirmNewsletterSubscriptionData:
type: object
additionalProperties: false
required:
- token
properties:
token:
type: string
minLength: 1
maxLength: 512
description: Opaque confirmation capability returned only in the confirmation email fragment.
example: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
UserTierData:
type: string
description:
"The user's subscription tier, which determines limits and feature access (e.g. max watchlist entries,
max search filters, allowed search filter fields).
- `FREE`: Default tier for all users. Allows up to 20 watchlist entries, up to 1 search filter (limited to `productQuery`,
`price`, `state`, `excludeProductId`, and `lifecycle` filter fields), and up to 10 product matches per filter.
- `PRO`: Premium tier. Allows up to 100 watchlist entries, up to 5 search filters with access to all filter fields,
and unlimited product matches per filter.
- `ULTIMATE`: Highest tier. Allows unlimited watchlist entries, unlimited search filters with access to all filter
fields, and unlimited product matches per filter.
"
enum:
- FREE
- PRO
- ULTIMATE
example: FREE
UserRoleData:
type: string
description: "The user's role used for API authorization.
- `USER`: Standard authenticated user.
- `ADMIN`: Administrator with access to admin-only endpoints.
"
enum:
- USER
- ADMIN
example: USER
NotificationData:
type: object
required:
- notificationId
- kind
- payload
- seen
- created
- updated
properties:
notificationId:
type: string
kind:
type: string
enum:
- WATCHLIST_PRICE_CHANGED
- WATCHLIST_AVAILABILITY_CHANGED
- SEARCH_FILTER_MATCH
- PARTNERSHIP_APPLICATION_APPROVED
- PARTNERSHIP_APPLICATION_REJECTED
payload:
$ref: "#/components/schemas/NotificationPayloadData"
seen:
type: boolean
created:
type: string
format: date-time
updated:
type: string
format: date-time
NotificationPayloadData:
description: Reason-specific immutable snapshot. Its shape is selected by the parent `NotificationData.kind`.
oneOf:
- $ref: "#/components/schemas/WatchlistNotificationPayloadData"
- $ref: "#/components/schemas/SearchFilterNotificationPayloadData"
- $ref: "#/components/schemas/PartnershipApplicationNotificationPayloadData"
WatchlistNotificationPayloadData:
type: object
required:
- productListingId
- listingSourceId
- sourceListingId
- listingSourceSlugId
- productListingTitleSlugId
- listingSourceName
- title
- image
- url
- viewUrl
- change
properties:
productListingId:
type: string
listingSourceId:
type: string
sourceListingId:
type: string
listingSourceSlugId:
type: string
productListingTitleSlugId:
type: string
listingSourceName:
type: string
title:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
image:
allOf:
- $ref: "#/components/schemas/ProductListingImageData"
nullable: true
url:
type: string
format: uri
viewUrl:
type: string
format: uri
change:
$ref: "#/components/schemas/WatchlistNotificationChangeData"
WatchlistNotificationChangeData:
oneOf:
- $ref: "#/components/schemas/WatchlistNotificationPriceChangeData"
- $ref: "#/components/schemas/WatchlistNotificationAvailabilityChangeData"
WatchlistNotificationPriceChangeData:
type: object
required:
- type
- oldPrice
- newPrice
properties:
type:
type: string
enum:
- PRICE_CHANGE
oldPrice:
allOf:
- $ref: "#/components/schemas/ProductListingPriceData"
nullable: true
description: Previous asking-price assertion. Null when unavailable.
newPrice:
allOf:
- $ref: "#/components/schemas/ProductListingPriceData"
nullable: true
description: New asking-price assertion. Null when unavailable.
WatchlistNotificationAvailabilityChangeData:
type: object
required:
- type
- oldAvailability
- newAvailability
properties:
type:
type: string
enum:
- AVAILABILITY_CHANGE
oldAvailability:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
newAvailability:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
SearchFilterNotificationPayloadData:
type: object
required:
- productListingId
- userSearchFilterId
- userSearchFilterName
- listingSourceId
- sourceListingId
- listingSourceSlugId
- productListingTitleSlugId
- listingSourceName
- title
- image
- url
- viewUrl
properties:
productListingId:
type: string
userSearchFilterId:
type: string
userSearchFilterName:
type: string
listingSourceId:
type: string
sourceListingId:
type: string
listingSourceSlugId:
type: string
productListingTitleSlugId:
type: string
listingSourceName:
type: string
title:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
image:
allOf:
- $ref: "#/components/schemas/ProductListingImageData"
nullable: true
url:
type: string
format: uri
viewUrl:
type: string
format: uri
PartnershipApplicationNotificationPayloadData:
type: object
required:
- partnershipApplicationId
- decision
- listingSourceName
- image
properties:
partnershipApplicationId:
type: string
decision:
type: string
enum:
- APPROVED
- REJECTED
listingSourceName:
type: string
image:
type: string
format: uri
nullable: true
UpdateNotificationSeenData:
type: object
required:
- seen
properties:
seen:
type: boolean
UpdateNotificationsSeenData:
type: object
required:
- notificationIds
- seen
properties:
notificationIds:
type: array
minItems: 1
items:
type: string
seen:
type: boolean
NotificationCollectionData:
type: object
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/NotificationData"
size:
type: integer
minimum: 0
maximum: 100
description: Number of items returned in the current page.
searchAfter:
type: array
nullable: true
minItems: 2
maxItems: 2
items:
type: string
description:
Opaque `[created RFC3339 timestamp, Notification ID]` cursor for the next page; omitted when no further
page exists.
CreateProductListingData:
type: object
additionalProperties: false
description:
"Data for creating a single product via the partner batch-create endpoint.
"
required:
- sourceListingId
- url
- images
properties:
sourceListingId:
type: string
description: The listing source's own identifier for the product. Must be unique within the listing source.
example: baroque-violin-001
title:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
description: Optional localized title. Omit or send `null` when no title is available.
description:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
description: Optional localized description. Omit or send `null` when no description is available.
price:
allOf:
- $ref: "#/components/schemas/ProductListingPriceData"
nullable: true
description: Optional asking-price assertion for the product.
priceEstimateMin:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
description: Optional lower bound of the estimated price range
priceEstimateMax:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
description: Optional upper bound of the estimated price range
availability:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
description: Omit or send `null` when Aura has no reliable current availability assertion.
url:
type: string
format: uri
description: URL to the product on the listing source's website
example: https://my-listing-source.com/product-listings/baroque-violin
images:
type: array
items:
type: string
format: uri
description: List of image URLs for the product. May be empty.
example:
- https://my-listing-source.com/images/violin-1.jpg
- https://my-listing-source.com/images/violin-2.jpg
auction:
allOf:
- $ref: "#/components/schemas/ProductListingAuctionData"
description: Omit for no Auction or lot changes, or send an asserted nested Auction/lot-facts patch. `null` is invalid. `auctionId` must identify an existing Auction for this ListingSource.
AsyncProductListingBatchReport:
type: object
additionalProperties: false
description: Admission report, not a listing creation or update result. For every evaluated batch, acceptedCount plus the number of failures equals the original array length.
required: [submissionId, acceptedCount, failures]
properties:
submissionId:
type: string
description: Opaque correlation identifier only; not a status resource or batch deduplication token.
example: plis1_example
acceptedCount:
type: integer
minimum: 0
maximum: 100
description: Number of publisher-confirmed admitted entries; never includes unconfirmed sends.
failures:
type: array
maxItems: 100
description: Exactly one per non-confirmed original entry, sorted by original zero-based index. Empty for fully admitted or empty batches.
items:
$ref: "#/components/schemas/AsyncProductListingBatchFailure"
AsyncProductListingBatchFailure:
type: object
additionalProperties: false
required: [index, error, retryable]
properties:
index:
type: integer
minimum: 0
maximum: 99
description: Original zero-based batch position, authoritative even when sourceListingId cannot be echoed.
sourceListingId:
type: string
description: Included only if present, valid, and safe to echo; omitted otherwise.
error:
type: string
pattern: "^[A-Z][A-Z0-9_]*$"
description: Bounded safe code, never raw exception or payload text. Includes BAD_BODY_VALUE, PRODUCT_LISTING_INGESTION_PAYLOAD_TOO_LARGE, ENQUEUE_FAILED (definitely unsuccessful send), ENQUEUE_UNCONFIRMED (possibly queued), ENQUEUE_NOT_ATTEMPTED (budget before send), ENQUEUE_BLOCKED (eligible FIFO successor held), PRODUCT_LISTING_INGESTION_INTERNAL_ERROR, and applicable narrower item-validation codes.
example: ENQUEUE_UNCONFIRMED
retryable:
type: boolean
description: Whether unchanged-whole-batch retry is appropriate; never permission to resubmit a compacted subset with the same key. Unconfirmed is retryable; validation and size errors are not. Blocked inherits its predecessor's retryability; deterministic configuration errors need repair.
PartnerProductListingBatchFailuresResponse:
type: array
description:
"Failed entries from a synchronous partner-product batch. This response body is returned
with HTTP 200 only when at least one entry in a non-empty batch succeeded.
"
items:
type: object
required:
- listingSourceId
- sourceListingId
- error
properties:
listingSourceId:
type: string
description: ListingSource that owns the failed product entry.
sourceListingId:
type: string
description: Partner-controlled identifier of the failed product entry.
error:
type: string
description: Stable API error key for the failed product entry.
example: PRODUCT_LISTING_NOT_FOUND
example:
- listingSourceId: ls_6rd827eqfefsva9teecmwa3ate
sourceListingId: baroque-violin-002
error: PRODUCT_LISTING_NOT_FOUND
WithdrawProductListingData:
type: object
required:
- sourceListingId
properties:
sourceListingId:
type: string
description: Partner-controlled identifier of the ProductListing to withdraw.
example: baroque-violin-001
UpdateProductListingData:
type: object
additionalProperties: false
description:
"Data for updating one ProductListing, synchronously or via async submission. Omitted fields remain unchanged.
`availability: null` clears the current assertion and `price: null` clears price. Omit `auction` to preserve
its context; `auction: null`, `url: null`, and `images: null` are invalid. Send `images: []` to remove all images.
"
required:
- sourceListingId
properties:
sourceListingId:
type: string
description: The listing source's own identifier for the product to update. Product existence is evaluated synchronously on the synchronous route and downstream on the async route.
example: baroque-violin-001
price:
allOf:
- $ref: "#/components/schemas/ProductListingPriceData"
nullable: true
description: Omit to leave unchanged. Send null to clear the current asking-price assertion.
availability:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
description: Omit to leave unchanged. Send null to clear the current assertion.
priceEstimateMin:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
description: Omit to leave unchanged. Send null to clear the current value.
priceEstimateMax:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
description: Omit to leave unchanged. Send null to clear the current value.
url:
type: string
format: uri
description: Omit to leave unchanged. Null is invalid.
example: https://my-listing-source.com/product-listings/baroque-violin
images:
type: array
items:
type: string
format: uri
description: Omit to leave unchanged. Send [] to remove all images; null is invalid.
example:
- https://my-listing-source.com/images/violin-1.jpg
auction:
allOf:
- $ref: "#/components/schemas/ProductListingAuctionData"
description: Omit to leave unchanged. Send an object to apply nested lot/timing leaf patches. `auctionId` must identify an existing Auction for this ListingSource; omit it to preserve membership, send null to clear it, or send an ID to set it. `null` for `auction` is invalid.
UpsertProductListingData:
type: object
additionalProperties: false
description:
"Data for synchronously upserting one ProductListing. Only `sourceListingId` is required.
Availability, price, and each price estimate are tri-state: omitted preserves an existing
value, `null` clears it, and a concrete value replaces it. The nested Auction/lot-facts patch is omitted
to preserve stored facts or supplied as a leaf patch; `null` is invalid. Within an asserted patch, lot/timing leaves
omit to preserve, use `null` to clear, or provide a value to set. `auctionId` must identify an existing Auction for this ListingSource; omit it to preserve membership, send `null` to clear it, or send an ID to set it. Upsert restores a withdrawn listing before current
facts apply. Images and URL use the field-specific rules documented below.
"
required:
- sourceListingId
properties:
sourceListingId:
type: string
description: The listing source's own identifier for the product. Must be unique within the listing source.
example: baroque-violin-001
title:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
description: Optional localized title for the product. Used only when creating a new product.
description:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
description: Optional localized description of the product. Used only when creating a new product.
price:
allOf:
- $ref: "#/components/schemas/ProductListingPriceData"
nullable: true
description:
Optional current asking-price assertion. Omit to leave it unchanged; send null to clear it; send a
tagged monetary or on-request value to set it. On creation, omitted and null both mean no assertion.
priceEstimateMin:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
description:
Optional lower bound of the estimated price range. On an existing listing, omit to preserve, send `null`
to clear, or send a value to set. On creation, omitted and `null` both mean no lower bound.
priceEstimateMax:
allOf:
- $ref: "#/components/schemas/PriceData"
nullable: true
description:
Optional upper bound of the estimated price range. On an existing listing, omit to preserve, send `null`
to clear, or send a value to set. On creation, omitted and `null` both mean no upper bound.
availability:
allOf:
- $ref: "#/components/schemas/ListingAvailabilityData"
nullable: true
description: Omit to preserve an existing assertion; send null to clear it; send a code to set it.
url:
type: string
format: uri
nullable: true
description:
URL to the product on the listing source's website. On an existing listing, omit or send `null` to
preserve the current URL; send a value to replace it. URL is non-clearable.
example: https://my-listing-source.com/product-listings/baroque-violin
images:
type: array
items:
type: string
format: uri
description:
List of image URLs for the product. On an existing listing, omit to preserve the stored image set,
send `[]` to clear it, or send an array to replace it. `null` is invalid.
example:
- https://my-listing-source.com/images/violin-1.jpg
- https://my-listing-source.com/images/violin-2.jpg
auction:
allOf:
- $ref: "#/components/schemas/ProductListingAuctionData"
description: Omit to preserve the current context or send an object to apply nested leaf patches. `auctionId` must identify an existing Auction for this ListingSource; omit it to preserve membership, send null to clear it, or send an ID to set it. `null` for `auction` is invalid.
WoocommerceProductWebhookImageData:
type: object
description: Image object extracted from a WooCommerce product payload.
required:
- src
properties:
src:
type: string
format: uri
description: Absolute URL of a product image.
example: https://aura-historia-test.local/wp-content/uploads/2026/05/product.jpg
WoocommerceProductWebhookUpsertData:
type: object
description:
"WooCommerce product payload accepted for `product.created` and `product.updated`.
Every event requires `id`. `status: publish` captures an UPSERT and requires nonblank `name` and `permalink`.
`status: trash`, `draft`, `pending`, or `private` captures a DELETE and requires only `id`; missing or
unsupported status is authorized ignored input and also requires only `id`.
"
required:
- id
properties:
id:
type: integer
format: int64
minimum: 0
description: WooCommerce product identifier. It is converted to the internal `sourceListingId`.
example: 17
name:
type: string
description: "Nonblank product title required only when `status: publish` captures an UPSERT."
example: Test Produkt Titel
permalink:
type: string
format: uri
description: "Public URL required only when `status: publish` captures an UPSERT."
example: http://aura-historia-test.local/product/test-produkt-titel/
description:
type: string
nullable: true
description: Optional WooCommerce product-description field. Accepted but ignored; it is not mapped to Aura's canonical description and is omitted from persisted source evidence.
example: "Hayde yallah test beschreibung
"
short_description:
type: string
nullable: true
description: Optional WooCommerce short-description field. Accepted but ignored; it is not mapped to Aura's canonical description and is omitted from persisted source evidence.
example: "Hayde yallah kurze test beschreibung
"
price:
type: string
nullable: true
pattern: '^(?:[0-9]+(?:\.[0-9]+)?|)$'
description:
"Optional WooCommerce price string for a captured `status: publish` UPSERT.
Intake writes current raw-values schema `1` with `MACHINE_DECIMAL`. A nonblank value must be an untrimmed unsigned ASCII decimal
(`digits` or `digits.digits`): no whitespace, signs, grouping separators, or currency symbols. A nonblank
`SET` requires the listing source's configured `woocommerceCurrency`. Fractional digits beyond the configured
currency minor-unit scale are accepted only when every excess digit is `0`; a nonzero excess digit is
rejected rather than truncated. A blank source string maps to `CLEAR`.
"
example: "42.69"
status:
type: string
nullable: true
description: "Optional WooCommerce product status string.
`publish` captures an UPSERT and requires nonblank `name` and `permalink`. `draft`, `pending`,
`private`, and `trash` capture a DELETE and require only `id`. Unsupported or missing status is
authorized ignored input: it causes no destructive write and does not require `name` or `permalink`.
"
example: publish
stock_status:
type: string
nullable: true
description: "Optional WooCommerce stock-status string.
For `publish`, `instock` maps to `IN_STOCK`, `outofstock` to `OUT_OF_STOCK`, and
`onbackorder` to `BACK_ORDER`. Missing or unsupported stock status never implies a sale.
"
example: instock
date_modified_gmt:
type: string
nullable: true
description: Optional WooCommerce product modification timestamp. When the topic/status maps to raw capture, accepted forms are no-offset GMT interpreted as UTC, RFC3339 `Z`, and RFC3339 `+00:00`; malformed or nonzero-offset values are rejected. A valid value establishes provider source order; omit it when no source-ordering guarantee is available.
example: "2026-09-06T12:34:56"
images:
type: array
description: Optional list of WooCommerce product images. Missing payload fields are treated as an empty list.
items:
$ref: "#/components/schemas/WoocommerceProductWebhookImageData"
example: []
WoocommerceProductWebhookDeleteData:
type: object
description: "WooCommerce product payload accepted for `product.deleted`.
Only `id` is required. If `name` or `permalink` are provided they may still be used by the backend,
but the event remains valid with just the product ID.
"
required:
- id
properties:
id:
type: integer
format: int64
minimum: 0
description: WooCommerce product identifier. It is converted to the internal `sourceListingId`.
example: 17
date_modified_gmt:
type: string
nullable: true
description: Optional WooCommerce product modification timestamp. Accepted forms are no-offset GMT interpreted as UTC, RFC3339 `Z`, and RFC3339 `+00:00`; nonzero offsets are rejected. A valid value establishes provider source order; omit it when no source-ordering guarantee is available.
example: "2026-09-06T12:34:56"
AdminOverviewData:
type: object
description: Versioned bounded administrator operational summary sourced from authoritative PostgreSQL.
required:
- schemaVersion
- users
- partnershipApplications
- parties
- listingSources
- partnerships
- productListings
properties:
schemaVersion:
type: integer
minimum: 1
enum: [1]
description: Response contract version.
users:
$ref: "#/components/schemas/AdminOverviewUsersData"
partnershipApplications:
$ref: "#/components/schemas/AdminOverviewPartnershipApplicationsData"
parties:
$ref: "#/components/schemas/AdminOverviewCountData"
listingSources:
$ref: "#/components/schemas/AdminOverviewListingSourcesData"
partnerships:
$ref: "#/components/schemas/AdminOverviewCountData"
productListings:
$ref: "#/components/schemas/AdminOverviewProductListingsData"
AdminOverviewCountData:
type: object
required: [total]
properties:
total:
type: integer
format: int64
minimum: 0
AdminOverviewUsersData:
type: object
required: [total, byTier, byRole]
properties:
total:
type: integer
format: int64
minimum: 0
byTier:
$ref: "#/components/schemas/AdminOverviewUserTierCountsData"
byRole:
$ref: "#/components/schemas/AdminOverviewUserRoleCountsData"
AdminOverviewUserTierCountsData:
type: object
required: [free, pro, ultimate]
properties:
free: { type: integer, format: int64, minimum: 0 }
pro: { type: integer, format: int64, minimum: 0 }
ultimate: { type: integer, format: int64, minimum: 0 }
AdminOverviewUserRoleCountsData:
type: object
required: [user, admin]
properties:
user: { type: integer, format: int64, minimum: 0 }
admin: { type: integer, format: int64, minimum: 0 }
AdminOverviewPartnershipApplicationsData:
type: object
required: [total, byState]
properties:
total:
type: integer
format: int64
minimum: 0
byState:
$ref: "#/components/schemas/AdminOverviewPartnershipApplicationStateCountsData"
AdminOverviewPartnershipApplicationStateCountsData:
type: object
required: [submitted, inReview, approved, rejected, withdrawn]
properties:
submitted: { type: integer, format: int64, minimum: 0 }
inReview: { type: integer, format: int64, minimum: 0 }
approved: { type: integer, format: int64, minimum: 0 }
rejected: { type: integer, format: int64, minimum: 0 }
withdrawn: { type: integer, format: int64, minimum: 0 }
AdminOverviewListingSourcesData:
type: object
description: "methodAssignments counts source-method rows and need not sum to total."
required: [total, withoutIngestionMethod, methodAssignments]
properties:
total:
type: integer
format: int64
minimum: 0
withoutIngestionMethod:
type: integer
format: int64
minimum: 0
methodAssignments:
$ref: "#/components/schemas/AdminOverviewListingSourceMethodAssignmentCountsData"
AdminOverviewListingSourceMethodAssignmentCountsData:
type: object
required: [webCrawl, shopify, woocommerce, partnerApi]
properties:
webCrawl: { type: integer, format: int64, minimum: 0 }
shopify: { type: integer, format: int64, minimum: 0 }
woocommerce: { type: integer, format: int64, minimum: 0 }
partnerApi: { type: integer, format: int64, minimum: 0 }
AdminOverviewProductListingsData:
type: object
description: Availability counts include ACTIVE listings only.
required:
[total, byLifecycle, activeAvailability, activeWithoutAvailability]
properties:
total:
type: integer
format: int64
minimum: 0
byLifecycle:
$ref: "#/components/schemas/AdminOverviewProductListingLifecycleCountsData"
activeAvailability:
$ref: "#/components/schemas/AdminOverviewActiveListingAvailabilityCountsData"
activeWithoutAvailability:
type: integer
format: int64
minimum: 0
AdminOverviewProductListingLifecycleCountsData:
type: object
required: [active, withdrawn]
properties:
active: { type: integer, format: int64, minimum: 0 }
withdrawn: { type: integer, format: int64, minimum: 0 }
AdminOverviewActiveListingAvailabilityCountsData:
type: object
required:
[
available,
inStock,
limitedAvailability,
backOrder,
madeToOrder,
preOrder,
preSale,
unavailable,
reserved,
outOfStock,
soldOut,
]
properties:
available: { type: integer, format: int64, minimum: 0 }
inStock: { type: integer, format: int64, minimum: 0 }
limitedAvailability: { type: integer, format: int64, minimum: 0 }
backOrder: { type: integer, format: int64, minimum: 0 }
madeToOrder: { type: integer, format: int64, minimum: 0 }
preOrder: { type: integer, format: int64, minimum: 0 }
preSale: { type: integer, format: int64, minimum: 0 }
unavailable: { type: integer, format: int64, minimum: 0 }
reserved: { type: integer, format: int64, minimum: 0 }
outOfStock: { type: integer, format: int64, minimum: 0 }
soldOut: { type: integer, format: int64, minimum: 0 }
AdminPartnershipCollectionData:
type: object
description: "Cursor-paginated safe Partnership summaries for the admin collection. `searchAfter` is omitted on the terminal page; no total is returned."
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/AdminPartnershipSummaryData"
description: Partnership summaries returned in the current page.
size:
type: integer
format: int64
minimum: 0
maximum: 100
description: Number of items returned in the current page.
example: 21
searchAfter:
type: array
minItems: 2
maxItems: 2
items:
type: string
description: Partnership cursor for the next page, omitted when no more results are available.
example:
- "2026-09-04T12:00:00Z"
- psh_3q65ndcw7wfxqswjtrv1kfhwd1
AdminPartnershipDetailsData:
type: object
description: "Administrator Partnership detail. Member and ListingSource reference arrays are ordered by ID and capped at 100 entries; count fields are complete."
required:
- partnershipId
- party
- memberUserIds
- listingSourceIds
- memberCount
- listingSourceGrantCount
- created
- updated
properties:
partnershipId:
type: string
description: Stable Partnership identifier.
party:
$ref: "#/components/schemas/PartnershipPartySummaryData"
memberUserIds:
type: array
maxItems: 100
uniqueItems: true
description: Current member User IDs in deterministic ascending ID order. At most 100 references are returned.
items:
type: string
listingSourceIds:
type: array
maxItems: 100
uniqueItems: true
description: Current ListingSource grant IDs in deterministic ascending ID order. At most 100 references are returned.
items:
type: string
memberCount:
type: integer
format: int64
minimum: 0
description: Complete number of current Partnership members.
listingSourceGrantCount:
type: integer
format: int64
minimum: 0
description: Complete number of current ListingSource grants.
created:
type: string
format: date-time
description: When the Partnership was created.
updated:
type: string
format: date-time
description: When the Partnership was last updated.
AdminPartnershipSummaryData:
type: object
description: "Safe administrator Partnership summary. Member/grant identities, Party contact data, persistence versions, and credentials are excluded."
required:
- partnershipId
- party
- memberCount
- listingSourceGrantCount
- created
- updated
properties:
partnershipId:
type: string
description: Stable Partnership identifier.
party:
$ref: "#/components/schemas/PartnershipPartySummaryData"
memberCount:
type: integer
format: int64
minimum: 0
description: Number of users in the Partnership.
listingSourceGrantCount:
type: integer
format: int64
minimum: 0
description: Number of ListingSource grants in the Partnership.
created:
type: string
format: date-time
description: When the Partnership was created.
updated:
type: string
format: date-time
description: When the Partnership was last updated.
PartnershipPartySummaryData:
type: object
description: Party summary embedded in an administrator Partnership result.
required:
- partyId
- partySlugId
- name
properties:
partyId:
type: string
description: Stable Party identifier.
partySlugId:
type: string
description: Immutable Party slug identifier.
name:
type: string
maxLength: 255
description: Party name.
PartnershipApplicationStateData:
type: string
enum:
- SUBMITTED
- IN_REVIEW
- APPROVED
- REJECTED
- WITHDRAWN
OwnPartnershipApplicationData:
type: object
required:
- id
- state
- proposal
properties:
id:
type: string
state:
$ref: "#/components/schemas/PartnershipApplicationStateData"
proposal:
$ref: "#/components/schemas/PartnershipApplicationProposalData"
AdminPartnershipApplicationData:
type: object
required:
- id
- applicantUserId
- state
- proposal
- approvedPartnershipId
- approvedListingSourceId
properties:
id:
type: string
applicantUserId:
type: string
state:
$ref: "#/components/schemas/PartnershipApplicationStateData"
proposal:
$ref: "#/components/schemas/PartnershipApplicationProposalData"
approvedPartnershipId:
type: string
nullable: true
approvedListingSourceId:
type: string
nullable: true
PartnershipProposalTypeData:
type: string
enum:
- EXISTING_LISTING_SOURCE
- PROPOSED_LISTING_SOURCE
AdminPartnershipApplicationSummaryData:
type: object
required:
- id
- applicantUserId
- state
- proposal
- approvedPartnershipId
- approvedListingSourceId
- created
- updated
properties:
id:
type: string
applicantUserId:
type: string
state:
$ref: "#/components/schemas/PartnershipApplicationStateData"
proposal:
$ref: "#/components/schemas/PartnershipApplicationProposalData"
approvedPartnershipId:
type: string
nullable: true
approvedListingSourceId:
type: string
nullable: true
created:
type: string
format: date-time
updated:
type: string
format: date-time
AdminPartnershipApplicationCollectionData:
type: object
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/AdminPartnershipApplicationSummaryData"
size:
type: integer
format: int64
minimum: 0
maximum: 100
description: Number of items returned in the current page.
searchAfter:
type: array
minItems: 2
maxItems: 2
items:
type: string
description: JSON cursor containing the sort timestamp followed by the PartnershipApplication ID.
total:
type: integer
format: int64
minimum: 0
nullable: true
ListingSourceReferenceData:
type: object
required:
- listingSourceId
- listingSourceSlugId
properties:
listingSourceId:
type: string
listingSourceSlugId:
type: string
example: ada-antiques
PublicListingSourceOperatorData:
type: object
required:
- name
properties:
name:
type: string
description: Original display name of the ListingSource operator Party. The operator is not a seller resource.
PublicListingSourceData:
type: object
description: Allowlisted public ListingSource card used by both public collection search and exact slug lookup. It omits Party identifiers/contact, ingestion/provider/referral configuration, timestamps, versions, and search metadata.
required:
- listingSourceId
- listingSourceSlugId
- name
- operator
properties:
listingSourceId:
type: string
description: Canonical `ls_` TypeID.
listingSourceSlugId:
type: string
description: Immutable navigation slug.
name:
type: string
operator:
$ref: "#/components/schemas/PublicListingSourceOperatorData"
url:
type: string
format: uri
description: Optional http/https presentation URL, omitted when absent.
image:
type: string
format: uri
description: Optional http/https presentation image URL, omitted when absent.
PublicListingSourceSearchCollectionData:
type: object
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/PublicListingSourceData"
size:
type: integer
minimum: 0
maximum: 50
description: Number of items returned in the current page.
searchAfter:
type: string
description: Opaque continuation, omitted on a terminal page.
ListingSourceData:
type: object
required:
- listingSourceId
- listingSourceSlugId
- name
- operator
- ingestionMethods
- created
- updated
properties:
listingSourceId:
type: string
listingSourceSlugId:
type: string
name:
type: string
description: ListingSource name. Outer Unicode whitespace is trimmed; blank values and values over 255 UTF-8 bytes are rejected.
operator:
$ref: "#/components/schemas/OperatorPartyData"
ingestionMethods:
type: array
items:
$ref: "#/components/schemas/ListingIngestionMethodData"
url:
type: string
format: uri
image:
type: string
format: uri
created:
type: string
format: date-time
updated:
type: string
format: date-time
AdministeredListingSourceData:
type: object
required:
- listingSourceId
- listingSourceSlugId
- name
properties:
listingSourceId:
type: string
listingSourceSlugId:
type: string
name:
type: string
ListingSourceSearchCollectionData:
type: object
description: "Cursor-paginated safe ListingSource summaries for the admin search endpoint. `searchAfter` is a ListingSource ID cursor and is omitted when the current page is terminal."
required:
- items
- size
properties:
items:
type: array
items:
$ref: "#/components/schemas/ListingSourceSearchSummaryData"
description: ListingSource summaries returned in the current page.
size:
type: integer
minimum: 0
maximum: 100
description: Number of items returned in the current page.
example: 21
searchAfter:
type: string
description: ListingSource ID cursor for the next page, omitted when no more results are available.
example: ls_11j55nbvjfe7ds34s7gya899a9
total:
type: integer
minimum: 0
description: Total matching ListingSources when provided by the reader; omitted otherwise.
example: 42
ListingSourceSearchSummaryData:
type: object
description: Safe ListingSource administration summary. Provider credentials, webhook secrets, and crawler-local configuration are excluded.
required:
- listingSourceId
- listingSourceSlugId
- name
- operator
- ingestionMethods
- presentation
- created
- updated
properties:
listingSourceId:
type: string
description: Stable ListingSource identifier.
listingSourceSlugId:
type: string
description: Immutable ListingSource slug identifier.
name:
type: string
description: ListingSource name.
operator:
$ref: "#/components/schemas/OperatorPartyData"
ingestionMethods:
type: array
items:
$ref: "#/components/schemas/ListingIngestionMethodData"
description: Active canonical ingestion methods.
presentation:
$ref: "#/components/schemas/ListingSourcePresentationData"
referralConfiguration:
allOf:
- $ref: "#/components/schemas/ReferralConfigurationData"
nullable: true
description: Safe referral summary; provider credentials are never included.
created:
type: string
format: date-time
updated:
type: string
format: date-time
ListingSourcePresentationData:
type: object
description: Optional public presentation URLs for a ListingSource.
properties:
url:
type: string
format: uri
image:
type: string
format: uri
ListingIngestionMethodData:
type: string
enum:
- WEB_CRAWL
- SHOPIFY
- WOOCOMMERCE
- PARTNER_API
PutWoocommerceListingSourceIngestionConfigurationData:
type: object
additionalProperties: false
required:
- webhookSecret
properties:
webhookSecret:
type: string
writeOnly: true
description: Required nonblank provider secret. Preserved exactly for HMAC verification and never returned.
currency:
allOf:
- $ref: "#/components/schemas/CurrencyData"
nullable: true
language:
allOf:
- $ref: "#/components/schemas/LanguageData"
nullable: true
PutShopifyListingSourceIngestionConfigurationData:
type: object
additionalProperties: false
required:
- domain
properties:
domain:
type: string
description: Valid Shopify store domain. Must be unique across ListingSources.
currency:
allOf:
- $ref: "#/components/schemas/CurrencyData"
nullable: true
language:
allOf:
- $ref: "#/components/schemas/LanguageData"
nullable: true
CreateListingIngestionConfigurationData:
oneOf:
- type: object
additionalProperties: false
required:
- type
- ingestionMethod
properties:
type:
type: string
enum:
- UNCONFIGURED
ingestionMethod:
$ref: "#/components/schemas/ListingIngestionMethodData"
- type: object
additionalProperties: false
required:
- type
properties:
type:
type: string
enum:
- WEB_CRAWL
fallbackCurrency:
type: string
description: Optional ISO 4217 fallback used only when crawler-extracted price text contains no currency hint.
- type: object
additionalProperties: false
required:
- type
- domain
properties:
type:
type: string
enum:
- SHOPIFY
domain:
type: string
currency:
type: string
language:
type: string
- type: object
additionalProperties: false
required:
- type
- webhookSecret
properties:
type:
type: string
enum:
- WOOCOMMERCE
webhookSecret:
type: string
writeOnly: true
description: Required nonblank WooCommerce secret. Never returned or logged.
currency:
type: string
language:
type: string
- type: object
additionalProperties: false
required:
- type
properties:
type:
type: string
enum:
- PARTNER_API
ReferralConfigurationData:
type: object
required:
- type
- camref
properties:
type:
type: string
enum:
- PARTNERIZE
camref:
type: string
OperatorPartyData:
type: object
required:
- partyId
- partySlugId
- name
properties:
partyId:
type: string
partySlugId:
type: string
name:
type: string
ListingSourceOperatorInputData:
oneOf:
- type: object
required:
- type
- partyId
properties:
type:
type: string
enum:
- EXISTING
partyId:
type: string
- type: object
required:
- type
- name
properties:
type:
type: string
enum:
- NEW
name:
type: string
description: Party name. Outer Unicode whitespace is trimmed; blank values and values over 255 UTF-8 bytes are rejected.
phone:
type: string
email:
type: string
format: email
CreateListingSourceData:
type: object
additionalProperties: false
required:
- name
- operator
- ingestionConfiguration
properties:
name:
type: string
description: ListingSource name. Outer Unicode whitespace is trimmed; blank values and values over 255 UTF-8 bytes are rejected.
operator:
$ref: "#/components/schemas/ListingSourceOperatorInputData"
ingestionConfiguration:
type: array
items:
$ref: "#/components/schemas/CreateListingIngestionConfigurationData"
url:
type: string
format: uri
image:
type: string
format: uri
referralConfiguration:
$ref: "#/components/schemas/ReferralConfigurationData"
UpdateListingIngestionConfigurationData:
oneOf:
- type: object
additionalProperties: false
required:
- type
properties:
type:
type: string
enum: [WEB_CRAWL]
fallbackCurrency:
type: string
- type: object
additionalProperties: false
required:
- type
- domain
properties:
type:
type: string
enum: [SHOPIFY]
domain:
type: string
currency:
type: string
language:
type: string
- type: object
additionalProperties: false
required:
- type
properties:
type:
type: string
enum: [WOOCOMMERCE]
webhookSecret:
type: string
writeOnly: true
description: Optional only when WooCommerce is already configured. Omission preserves the existing secret; a string rotates it. Null is invalid, and when adding WooCommerce a secret is required.
currency:
type: string
language:
type: string
- type: object
additionalProperties: false
required:
- type
properties:
type:
type: string
enum: [PARTNER_API]
UpdateListingSourceData:
type: object
additionalProperties: false
description: Omitted fields are unchanged. `null` clears only `url`, `image`, and `referralConfiguration`. Supplying ingestionConfiguration replaces the whole configuration list; a WooCommerce secret may be omitted only when preserving an existing WooCommerce configuration.
properties:
name:
type: string
description: ListingSource name. Outer Unicode whitespace is trimmed; blank values and values over 255 UTF-8 bytes are rejected.
ingestionConfiguration:
type: array
items:
$ref: "#/components/schemas/UpdateListingIngestionConfigurationData"
url:
type: string
format: uri
nullable: true
image:
type: string
format: uri
nullable: true
referralConfiguration:
allOf:
- $ref: "#/components/schemas/ReferralConfigurationData"
nullable: true
PartnershipApplicationProposalData:
oneOf:
- type: object
required:
- type
- listingSourceId
properties:
type:
type: string
enum:
- EXISTING_LISTING_SOURCE
listingSourceId:
type: string
- type: object
required:
- type
- party
- listingSource
properties:
type:
type: string
enum:
- PROPOSED_LISTING_SOURCE
party:
$ref: "#/components/schemas/ProposedPartyData"
listingSource:
$ref: "#/components/schemas/ProposedListingSourceData"
ProposedPartyData:
type: object
required:
- name
properties:
name:
type: string
description: Party name. Outer Unicode whitespace is trimmed; blank values and values over 255 UTF-8 bytes are rejected.
phone:
type: string
email:
type: string
format: email
ProposedListingSourceData:
type: object
required:
- name
- requestedIngestionMethods
properties:
name:
type: string
description: ListingSource name. Outer Unicode whitespace is trimmed; blank values and values over 255 UTF-8 bytes are rejected.
url:
type: string
format: uri
image:
type: string
format: uri
requestedIngestionMethods:
type: array
items:
$ref: "#/components/schemas/ListingIngestionMethodData"
SubmitPartnershipApplicationData:
type: object
required:
- proposal
properties:
proposal:
$ref: "#/components/schemas/PartnershipApplicationProposalData"
DecidePartnershipApplicationData:
type: object
required:
- decision
properties:
decision:
type: string
enum:
- APPROVE
- REJECT
CreateAuctionData:
type: object
additionalProperties: false
required: [listingSourceId, sourceAuctionId]
properties:
listingSourceId:
type: string
description: Strict ListingSource TypeID.
sourceAuctionId:
type: string
maxLength: 512
description: 1–512 UTF-8 bytes after outer Unicode-whitespace trimming; case and internal whitespace are preserved.
name:
$ref: "#/components/schemas/LocalizedTextData"
catalogueUrl:
type: string
format: uri
format:
$ref: "#/components/schemas/AuctionFormatData"
schedule:
$ref: "#/components/schemas/AuctionScheduleInputData"
reportedStatus:
$ref: "#/components/schemas/AuctionReportedStatusData"
reportedLotCount:
type: integer
format: int64
minimum: 0
maximum: 4294967295
UpdateAuctionData:
type: object
additionalProperties: false
required: [expectedVersion]
description: Omitted members are unchanged. Nullable members explicitly clear their value.
properties:
expectedVersion:
type: integer
format: int64
minimum: 1
name:
allOf: [{ $ref: "#/components/schemas/LocalizedTextData" }]
nullable: true
catalogueUrl:
type: string
format: uri
nullable: true
format:
allOf: [{ $ref: "#/components/schemas/AuctionFormatData" }]
nullable: true
schedule:
$ref: "#/components/schemas/AuctionSchedulePatchData"
reportedStatus:
allOf: [{ $ref: "#/components/schemas/AuctionReportedStatusData" }]
nullable: true
reportedLotCount:
type: integer
format: int64
minimum: 0
maximum: 4294967295
nullable: true
PublicAuctionDirectoryData:
type: object
additionalProperties: false
required: [items, pageSize]
properties:
items:
type: array
items:
$ref: "#/components/schemas/PublicAuctionDirectoryItemData"
pageSize:
type: integer
format: int64
minimum: 1
maximum: 100
searchAfter:
allOf:
- $ref: "#/components/schemas/PublicAuctionDirectoryCursorData"
nullable: true
description: Omitted on the terminal page. Send the complete JSON value as the `searchAfter` query parameter.
PublicAuctionDirectoryItemData:
type: object
additionalProperties: false
required:
[
auctionId,
listingSource,
name,
format,
schedule,
reportedStatus,
created,
]
properties:
auctionId:
type: string
description: Strict `auc_` UUIDv7 TypeID.
listingSource:
$ref: "#/components/schemas/PublicAuctionSourceData"
name:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
format:
allOf:
- $ref: "#/components/schemas/AuctionFormatData"
nullable: true
schedule:
$ref: "#/components/schemas/AuctionScheduleData"
reportedStatus:
allOf:
- $ref: "#/components/schemas/AuctionReportedStatusData"
nullable: true
created:
type: string
format: date-time
PublicAuctionData:
type: object
additionalProperties: false
required:
[
auctionId,
listingSource,
name,
catalogueUrl,
viewUrl,
format,
schedule,
reportedStatus,
reportedLotCount,
visibleListingCount,
]
properties:
auctionId:
type: string
description: Strict `auc_` UUIDv7 TypeID.
listingSource:
$ref: "#/components/schemas/PublicAuctionSourceData"
name:
allOf:
- $ref: "#/components/schemas/LocalizedTextData"
nullable: true
catalogueUrl:
type: string
format: uri
nullable: true
viewUrl:
type: string
format: uri
nullable: true
format:
allOf:
- $ref: "#/components/schemas/AuctionFormatData"
nullable: true
schedule:
$ref: "#/components/schemas/AuctionScheduleData"
reportedStatus:
allOf:
- $ref: "#/components/schemas/AuctionReportedStatusData"
nullable: true
reportedLotCount:
type: integer
format: int64
minimum: 0
nullable: true
visibleListingCount:
type: integer
format: int64
minimum: 0
PublicAuctionSourceData:
type: object
additionalProperties: false
required: [listingSourceId, name, slugId]
properties:
listingSourceId:
type: string
name:
type: string
slugId:
type: string
AdminAuctionSearchCollectionData:
type: object
additionalProperties: false
required: [items, size]
properties:
items:
type: array
items: { $ref: "#/components/schemas/AuctionAdminData" }
size:
type: integer
description: Number of items returned on this page.
searchAfter:
type: string
description: Opaque cursor, omitted on the terminal page.
PublicAuctionDirectoryCursorData:
type: object
additionalProperties: false
required: [created, auctionId, scope]
properties:
created:
type: string
format: date-time
auctionId:
type: string
scheduled:
type: string
format: date-time
nullable: true
description: Present for scheduled sorting; null if the selected role instant is missing. Omitted for created sorting.
scope:
$ref: "#/components/schemas/PublicAuctionDirectoryCursorScopeData"
PublicAuctionDirectoryCursorScopeData:
type: object
additionalProperties: false
required: [listingSourceId, format, reportedStatus, timeRole, from, to]
properties:
listingSourceId:
type: string
nullable: true
format:
allOf:
- $ref: "#/components/schemas/AuctionFormatData"
nullable: true
reportedStatus:
allOf:
- $ref: "#/components/schemas/AuctionReportedStatusData"
nullable: true
timeRole:
type: string
enum: [BIDDING_OPENS, LIVE_STARTS, LOTS_BEGIN_CLOSING, SCHEDULED_END]
nullable: true
sort:
type: string
enum: [scheduled]
description: Omitted for the default created ordering.
order:
type: string
enum: [asc, desc]
description: Omitted for the default created/descending ordering.
from:
type: string
format: date-time
nullable: true
to:
type: string
format: date-time
nullable: true
PublicAuctionCatalogueData:
type: object
additionalProperties: false
required: [items, pageSize]
properties:
items:
type: array
items:
$ref: "#/components/schemas/PersonalizedProductListingDetailsData"
pageSize:
type: integer
format: int64
minimum: 1
maximum: 100
searchAfter:
allOf:
- $ref: "#/components/schemas/PublicAuctionCatalogueCursorData"
nullable: true
description: Omitted on the terminal page. Send the complete JSON value as the `searchAfter` query parameter.
PublicAuctionCatalogueCursorData:
type: object
additionalProperties: false
required: [auctionId, cataloguePosition, productListingId]
properties:
auctionId:
type: string
cataloguePosition:
type: integer
format: int64
minimum: 1
nullable: true
productListingId:
type: string
AuctionAdminData:
type: object
required:
[
auctionId,
listingSourceId,
sourceAuctionId,
name,
catalogueUrl,
format,
schedule,
reportedStatus,
reportedLotCount,
expectedVersion,
created,
updated,
]
properties:
auctionId: { type: string, description: Strict `auc_` UUIDv7 TypeID. }
listingSourceId: { type: string }
sourceAuctionId: { type: string }
name:
allOf: [{ $ref: "#/components/schemas/LocalizedTextData" }]
nullable: true
catalogueUrl: { type: string, format: uri, nullable: true }
format:
allOf: [{ $ref: "#/components/schemas/AuctionFormatData" }]
nullable: true
schedule: { $ref: "#/components/schemas/AuctionScheduleData" }
reportedStatus:
allOf: [{ $ref: "#/components/schemas/AuctionReportedStatusData" }]
nullable: true
reportedLotCount: { type: integer, format: int64, nullable: true }
expectedVersion: { type: integer, format: int64, minimum: 1 }
created: { type: string, format: date-time }
updated: { type: string, format: date-time }
AuctionFormatData:
type: string
enum: [LIVE, TIMED]
AuctionReportedStatusData:
type: string
enum: [SCHEDULED, IN_PROGRESS, ENDED, POSTPONED, CANCELLED]
AuctionSummaryData:
type: object
additionalProperties: false
required: [auctionId, schedule]
description: Safe current parent Auction presentation included by PostgreSQL full-detail ProductListing reads.
properties:
auctionId:
type: string
description: Strict `auc_` UUIDv7 TypeID.
name:
allOf: [{ $ref: "#/components/schemas/LocalizedTextData" }]
nullable: true
format:
allOf: [{ $ref: "#/components/schemas/AuctionFormatData" }]
nullable: true
reportedStatus:
allOf: [{ $ref: "#/components/schemas/AuctionReportedStatusData" }]
nullable: true
schedule:
$ref: "#/components/schemas/AuctionScheduleData"
AuctionScheduleData:
type: object
additionalProperties: false
required: [biddingOpens, liveStarts, lotsBeginClosing, scheduledEnd]
properties:
biddingOpens: { type: string, format: date-time, nullable: true }
liveStarts: { type: string, format: date-time, nullable: true }
lotsBeginClosing: { type: string, format: date-time, nullable: true }
scheduledEnd: { type: string, format: date-time, nullable: true }
AuctionScheduleInputData:
type: object
additionalProperties: false
description: Sparse Auction create schedule. Omitted roles remain absent.
properties:
biddingOpens: { type: string, format: date-time, nullable: true }
liveStarts: { type: string, format: date-time, nullable: true }
lotsBeginClosing: { type: string, format: date-time, nullable: true }
scheduledEnd: { type: string, format: date-time, nullable: true }
AuctionSchedulePatchData:
type: object
additionalProperties: false
description: Omitted roles are unchanged; `null` clears an asserted RFC3339 instant.
properties:
biddingOpens: { type: string, format: date-time, nullable: true }
liveStarts: { type: string, format: date-time, nullable: true }
lotsBeginClosing: { type: string, format: date-time, nullable: true }
scheduledEnd: { type: string, format: date-time, nullable: true }
ProductListingSourceData:
type: object
description: ListingSource presentation hydrated for a ProductListing response.
required:
- listingSourceId
- name
- slugId
properties:
listingSourceId:
type: string
name:
type: string
slugId:
type: string
UserAddressId:
type: string
pattern: ^uaddr_[0-7][0-9a-hjkmnp-tv-z]{25}$
description: Strict server-generated UUIDv7 UserAddress TypeID, returned on creation. No bare UUID or owner input.
UserAddressLabel:
type: string
minLength: 1
maxLength: 128
description: Nonblank private label, at most 128 UTF-8 bytes, without control characters.
UserAddressGeography:
allOf:
- $ref: '#/components/schemas/PartyLocationGeography'
- type: object
required:
- addressText
properties:
addressText:
type: string
nullable: false
minLength: 1
maxLength: 4096
description: Verbatim free-text geographic assertions. addressText is required and non-null; no parsed street
or PlaceId. Provider-derived values remain separate.
CreateUserAddress:
type: object
additionalProperties: false
required:
- label
- geography
properties:
label:
$ref: '#/components/schemas/UserAddressLabel'
geography:
$ref: '#/components/schemas/UserAddressGeography'
UpdateUserAddress:
type: object
additionalProperties: false
required:
- expectedVersion
- label
- geography
properties:
expectedVersion:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
label:
$ref: '#/components/schemas/UserAddressLabel'
geography:
$ref: '#/components/schemas/UserAddressGeography'
UserAddressExpectedVersion:
type: object
additionalProperties: false
required:
- expectedVersion
properties:
expectedVersion:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
UserAddress:
type: object
additionalProperties: false
required:
- addressId
- label
- geography
- inputRevision
- version
- preferred
- resolution
properties:
addressId:
$ref: '#/components/schemas/UserAddressId'
label:
$ref: '#/components/schemas/UserAddressLabel'
geography:
$ref: '#/components/schemas/UserAddressGeography'
inputRevision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
version:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
preferred:
type: boolean
resolution:
$ref: '#/components/schemas/UserAddressResolution'
UserAddressPage:
type: object
additionalProperties: false
required:
- items
- next
properties:
items:
type: array
items:
$ref: '#/components/schemas/UserAddress'
maxItems: 100
next:
allOf:
- $ref: '#/components/schemas/UserAddressId'
nullable: true
BrowsingDestination:
oneOf:
- type: object
additionalProperties: false
required:
- kind
properties:
kind:
type: string
enum:
- NONE
- type: object
additionalProperties: false
required:
- kind
- addressId
properties:
kind:
type: string
enum:
- ADDRESS
addressId:
$ref: '#/components/schemas/UserAddressId'
- type: object
additionalProperties: false
required:
- kind
- country
properties:
kind:
type: string
enum:
- COUNTRY_POSTAL
country:
type: string
pattern: ^[A-Z]{2}$
description: Current ISO alpha-2 assertion; never inferred from language/currency/IP.
postalCode:
type: string
nullable: true
minLength: 1
maxLength: 64
description: Optional verbatim postal assertion, at most 64 UTF-8 bytes.
description: Exclusive browsing selector. An ADDRESS reference must belong to the current user. No shipping, billing
or residence assertion.
BrowsingDestinationView:
type: object
additionalProperties: false
required:
- version
- destination
properties:
version:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
destination:
$ref: '#/components/schemas/BrowsingDestination'
SetBrowsingDestination:
type: object
additionalProperties: false
required:
- expectedVersion
- destination
properties:
expectedVersion:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
destination:
$ref: '#/components/schemas/BrowsingDestination'
UserAddressDerivedGeography:
type: object
additionalProperties: false
required:
- geography
- position
properties:
geography:
allOf:
- $ref: '#/components/schemas/PartyLocationGeography'
nullable: true
position:
allOf:
- $ref: '#/components/schemas/PartyLocationPosition'
nullable: true
UserAddressResolution:
type: object
additionalProperties: false
description: Current backend geocoding state, returned with address CRUD/list reads. A unique compatible premises result can supply a point
automatically. Coarse results can supply administrative geography only. Expired or revoked evidence is UNAVAILABLE and suppressed. This is
browsing enrichment, not address or delivery verification.
required:
- status
- derived
- attribution
properties:
status:
type: string
enum:
- PENDING
- ACCEPTED
- AMBIGUOUS
- NO_MATCH
- FAILED
- BLOCKED
- UNAVAILABLE
derived:
allOf:
- $ref: '#/components/schemas/UserAddressDerivedGeography'
nullable: true
attribution:
allOf:
- $ref: '#/components/schemas/UserAddressAttribution'
nullable: true
UserAddressAttribution:
type: object
additionalProperties: false
required:
- provider
- attributionUrl
description: Display the attribution when showing accepted provider-derived geography.
properties:
provider:
type: string
attributionUrl:
type: string
format: uri
SourceLocationDefaultEvidence:
type: object
additionalProperties: false
required:
- reference
- scope
properties:
reference:
type: string
minLength: 1
maxLength: 2048
description: Nonblank opaque source-scoped observation, at most 2048 UTF-8 bytes,
without control or line-separator characters. Never fetched.
scope:
type: string
enum:
- ASSOCIATED_BUSINESS
- ADVERTISED_INVENTORY
SourceLocationDefaultAssignment:
type: object
additionalProperties: false
required:
- partyLocationId
properties:
partyLocationId:
$ref: '#/components/schemas/PartyLocationId'
businessAssociation:
allOf:
- $ref: '#/components/schemas/SourceLocationDefaultEvidence'
nullable: true
description: Explicit associated-business evidence; scope must be ASSOCIATED_BUSINESS.
advertisedInventory:
allOf:
- $ref: '#/components/schemas/SourceLocationDefaultEvidence'
nullable: true
description: Explicit inventory evidence; scope must be ADVERTISED_INVENTORY.
Business, legal or correspondence evidence alone never establishes this meaning.
SourceLocationDefaultData:
type: object
additionalProperties: false
required:
- listingSourceId
- revision
- assignment
- eligibility
properties:
listingSourceId:
type: string
pattern: ^ls_[0-7][0-9a-hjkmnp-tv-z]{25}$
revision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
description: Expected source-default revision; an untouched source has revision
1. Stale writes conflict, including no-ops.
assignment:
allOf:
- $ref: '#/components/schemas/SourceLocationDefaultAssignment'
nullable: true
eligibility:
type: string
enum:
- ACTIVE
- RETIRED
nullable: true
description: Current eligibility of the retained reference, null if no assignment.
Retirement preserves the reference but disables inherited geography.
AssignSourceLocationDefaultData:
type: object
additionalProperties: false
required:
- expectedRevision
- partyLocationId
properties:
expectedRevision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
description: Expected source-default revision; an untouched source has revision
1. Stale writes conflict, including no-ops.
partyLocationId:
$ref: '#/components/schemas/PartyLocationId'
businessAssociation:
allOf:
- $ref: '#/components/schemas/SourceLocationDefaultEvidence'
nullable: true
description: Explicit associated-business evidence; scope must be ASSOCIATED_BUSINESS.
advertisedInventory:
allOf:
- $ref: '#/components/schemas/SourceLocationDefaultEvidence'
nullable: true
description: Explicit inventory evidence; scope must be ADVERTISED_INVENTORY.
Business, legal or correspondence evidence alone never establishes this meaning.
description: Replaces the one reference and both applicability meanings atomically.
Omitted/null evidence means absent, including on replacement. No automatic location
selection.
ChangeSourceLocationDefaultApplicabilityData:
type: object
additionalProperties: false
required:
- expectedRevision
properties:
expectedRevision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
description: Expected source-default revision; an untouched source has revision
1. Stale writes conflict, including no-ops.
businessAssociation:
allOf:
- $ref: '#/components/schemas/SourceLocationDefaultEvidence'
nullable: true
description: Omitted retains the assertion; null removes it; set requires ASSOCIATED_BUSINESS
scope.
advertisedInventory:
allOf:
- $ref: '#/components/schemas/SourceLocationDefaultEvidence'
nullable: true
description: Omitted retains the assertion; null removes it; set requires ADVERTISED_INVENTORY
scope.
description: Changes applicability on the existing, active reference without changing
its location ID.
ClearSourceLocationDefaultData:
type: object
additionalProperties: false
required:
- expectedRevision
properties:
expectedRevision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
description: Expected source-default revision; an untouched source has revision
1. Stale writes conflict, including no-ops.
PartyLocationId:
type: string
pattern: ^ploc_[0-7][0-9a-hjkmnp-tv-z]{25}$
description: Strict UUIDv7 PartyLocation TypeID; bare UUIDs and foreign prefixes are rejected.
PartyLocationGeography:
type: object
additionalProperties: false
required:
- referenceRelease
properties:
referenceRelease:
type: string
enum:
- iso-codes-4.20.1
addressText:
type: string
maxLength: 4096
description: Verbatim free-text assertion; at most 4096 UTF-8 bytes. No geocoding or postal inference.
nullable: true
country:
type: string
pattern: ^[A-Z]{2}$
description: Exact current ISO alpha-2 country in the named immutable release.
nullable: true
subdivision:
type: string
description: Complete ISO 3166-2 code in the named release; must agree with country when supplied.
nullable: true
postalCode:
type: string
maxLength: 64
description: Single-line verbatim postal assertion, at most 64 UTF-8 bytes.
nullable: true
description: Partial caller assertions. At least one geographic field must be present and nonblank. Coordinates
are separate. No synchronous geocoding.
PartyLocationPosition:
type: object
additionalProperties: false
required:
- latitudeDegrees
- longitudeDegrees
- precision
properties:
latitudeDegrees:
type: number
minimum: -90
maximum: 90
longitudeDegrees:
type: number
minimum: -180
maximum: 180
precision:
type: string
enum:
- PREMISES
- STREET
- LOCALITY
- REPRESENTATIVE
accuracyMetres:
type: number
minimum: 0
nullable: true
description: Finite caller-asserted WGS84 coordinates with explicit precision. Not geocoder-derived evidence;
(0,0) is valid.
PartyLocationEvidence:
type: object
additionalProperties: false
required:
- reference
- scope
properties:
reference:
type: string
minLength: 1
maxLength: 2048
description: Opaque nonblank single-line evidence/source reference; never fetched. At most 2048 UTF-8 bytes.
observedAt:
type: string
format: date-time
nullable: true
scope:
type: string
enum:
- SITE_DESCRIPTION
- REGISTERED_ADDRESS
- CORRESPONDENCE_ADDRESS
description: Declared assertion scope; never caller identity, authorization or trust.
ExpectedPartyLocation:
type: object
additionalProperties: false
required:
- id
- revision
properties:
id:
$ref: '#/components/schemas/PartyLocationId'
revision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
CreatePartyLocationData:
type: object
additionalProperties: false
required:
- label
properties:
label:
type: string
minLength: 1
maxLength: 255
description: Trimmed nonblank single-line label, at most 255 UTF-8 bytes. Never establishes site identity.
roles:
type: array
maxItems: 4
uniqueItems: true
items:
type: string
enum:
- BUSINESS_PREMISES
- WAREHOUSE
- REGISTERED_ADDRESS
- CORRESPONDENCE
description: Business use of a site. No assertion about listing stock, dispatch or pickup.
default: []
geography:
allOf:
- $ref: '#/components/schemas/PartyLocationGeography'
nullable: true
position:
allOf:
- $ref: '#/components/schemas/PartyLocationPosition'
nullable: true
evidence:
allOf:
- $ref: '#/components/schemas/PartyLocationEvidence'
nullable: true
relocates:
allOf:
- $ref: '#/components/schemas/ExpectedPartyLocation'
nullable: true
description: Create an independently identified site with exact public geography. Optional relocates creates a new identity and retires the
referenced active site atomically; its Party and revision must match.
CorrectPartyLocationData:
type: object
additionalProperties: false
required:
- expectedRevision
- correction
properties:
label:
type: string
minLength: 1
maxLength: 255
description: Trimmed nonblank single-line label, at most 255 UTF-8 bytes. Never establishes site identity.
roles:
type: array
maxItems: 4
uniqueItems: true
items:
type: string
enum:
- BUSINESS_PREMISES
- WAREHOUSE
- REGISTERED_ADDRESS
- CORRESPONDENCE
description: Business use of a site. No assertion about listing stock, dispatch or pickup.
geography:
allOf:
- $ref: '#/components/schemas/PartyLocationGeography'
nullable: true
position:
allOf:
- $ref: '#/components/schemas/PartyLocationPosition'
nullable: true
evidence:
allOf:
- $ref: '#/components/schemas/PartyLocationEvidence'
nullable: true
expectedRevision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
correction:
type: string
enum:
- SAME_SITE
description: Same physical site correction only. Omitted members remain unchanged. Geography/position/evidence
null clears; non-null geographic objects replace the complete partial assertion. Label and roles
reject null. Roles [] clears the set. No-op at the current revision emits no change signal. Relocation uses
create with relocates.
SetPartyLocationLifecycleData:
type: object
additionalProperties: false
required:
- expectedRevision
- lifecycle
properties:
expectedRevision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
lifecycle:
type: string
enum:
- ACTIVE
- RETIRED
description: Explicit retirement (RETIRED) or restore (ACTIVE), with CAS. Retains references/history and never
auto-selects replacements.
PartyLocationData:
type: object
additionalProperties: false
required:
- id
- partyId
- label
- roles
- lifecycle
- revision
- inputRevision
properties:
id:
$ref: '#/components/schemas/PartyLocationId'
partyId:
type: string
pattern: ^pty_
label:
type: string
minLength: 1
maxLength: 255
description: Trimmed nonblank single-line label, at most 255 UTF-8 bytes. Never establishes site identity.
roles:
type: array
maxItems: 4
uniqueItems: true
items:
type: string
enum:
- BUSINESS_PREMISES
- WAREHOUSE
- REGISTERED_ADDRESS
- CORRESPONDENCE
description: Business use of a site. No assertion about listing stock, dispatch or pickup.
geography:
$ref: '#/components/schemas/PartyLocationGeography'
position:
$ref: '#/components/schemas/PartyLocationPosition'
lifecycle:
type: string
enum:
- ACTIVE
- RETIRED
revision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
inputRevision:
type: integer
format: int64
minimum: 1
maximum: 9223372036854775807
evidence:
$ref: '#/components/schemas/PartyLocationEvidence'
PartyLocationsPage:
type: object
additionalProperties: false
required:
- items
- next
properties:
items:
type: array
items:
$ref: '#/components/schemas/PartyLocationData'
next:
allOf:
- $ref: '#/components/schemas/PartyLocationId'
nullable: true
description: Last returned ID when another row exists; supply as after. Null when exhausted.
PartyLocationManagementGrantData:
type: object
additionalProperties: false
required:
- granted
properties:
granted:
type: boolean
description: true grants explicit management/private reads; false removes only the explicit grant. Active partnership membership independently authorizes access. Same-state commands are no-ops.
GeographicOriginData:
type: object
additionalProperties: false
required: [latitude, longitude]
description: Explicit finite numeric WGS 84 coordinates in degrees; no text, address or preference resolution.
properties:
latitude: {type: number, minimum: -90, maximum: 90}
longitude: {type: number, minimum: -180, maximum: 180}
GeographicRadiusData:
type: object
additionalProperties: false
required: [amount, unit]
description: >-
Finite positive radius in the supplied unit, equivalent to at most 20000 kilometres.
The supplied amount and unit are preserved in private saved-filter snapshots.
properties:
amount: {type: number, minimum: 0, exclusiveMinimum: true, example: 25}
unit:
type: string
enum: [KILOMETERS, MILES, METERS, YARDS, FEET, INCHES, CENTIMETERS, MILLIMETERS, NAUTICAL_MILES]
example: KILOMETERS
example: {amount: 25, unit: KILOMETERS}
GeographicSearchData:
type: object
additionalProperties: false
description: >-
At least one country, subdivision, radius or distance order is required. Sets are OR;
distinct geographic predicates are AND. Subdivisions must belong to a supplied country
when countries is nonempty. Absence excludes a result. Radius and ordering require an
explicit numeric origin; an origin or approximate mode without proximity is invalid.
Strict proximity admits PREMISES only; approximate also admits STREET, LOCALITY and
REPRESENTATIVE. Distance ordering is incompatible
with the existing sort. Saved filters retain a private immutable snapshot until replaced.
properties:
countries:
type: array
maxItems: 100
uniqueItems: true
items: {type: string, pattern: '^[A-Z]{2}$'}
example: [DE]
subdivisions:
type: array
maxItems: 100
uniqueItems: true
items: {type: string}
example: [DE-BY]
origin: {$ref: '#/components/schemas/GeographicOriginData'}
radius: {$ref: '#/components/schemas/GeographicRadiusData'}
mode: {type: string, enum: [STRICT, APPROXIMATE], default: STRICT}
distanceOrder: {type: string, enum: [ASC, DESC]}
ListingGeographyData:
type: object
required: [locationId, basis, referenceRelease]
description: >-
Public advertised-inventory geography selected by the backend. Distance is to recorded
evidence, not verified object position or journey distance. Display is rounded to
0.1 km for premises, 1 km for street and 10 km for locality/representative evidence.
properties:
locationId: {type: string}
basis: {type: string, enum: [SOURCE_DEFAULT_DERIVED]}
referenceRelease: {type: string}
country: {type: string}
subdivision: {type: string}
point: {$ref: '#/components/schemas/GeographicOriginData'}
precision: {type: string, enum: [PREMISES, STREET, LOCALITY, REPRESENTATIVE]}
distanceKm: {type: number, minimum: 0}
PartyLocationDiscoveryCursorData:
type: object
additionalProperties: false
required: [locationId]
description: Repeat with the same query. distanceKm is required exactly when ordering by distance; it is an unrounded continuation value.
properties:
locationId: {type: string}
distanceKm: {type: number, minimum: 0}
PublicPartyLocationData:
type: object
required: [partyId, partyName, locationId, label, basis]
properties:
partyId: {type: string}
partyName: {type: string}
locationId: {type: string}
label: {type: string}
basis: {type: string, enum: [CALLER_ASSERTED, ACCEPTED_DERIVED, MIXED_ASSERTED_AND_DERIVED]}
country: {type: string}
subdivision: {type: string}
point: {$ref: '#/components/schemas/GeographicOriginData'}
precision: {type: string, enum: [PREMISES, STREET, LOCALITY, REPRESENTATIVE]}
distanceKm: {type: number, minimum: 0, description: Rounded display distance following evidence precision.}
x-tagGroups:
- name: Operations
tags:
- Operations
- name: Discovery
tags:
- ProductListings
- ListingSources
- Auctions
- name: User Experience
tags:
- Search Filters
- Watchlist
- Notifications
- User Account
- Billing
- Newsletter
- name: Partner & Platform Integrations
tags:
- Partnerships
- PartnershipApplications
- OAuth
tags:
- name: Operations
description: Public process liveness and service readiness probes.
- name: Auctions
description: Public Auction discovery, catalogue reads, and administrator Auction management.
- name: ProductListings
description:
Product retrieval, product history, similar-product discovery, product search, and partner catalog ingestion
workflows.
- name: ListingSources
description: ListingSource retrieval, authenticated creation and update, and caller-administered listing sources.
- name: Search Filters
description: Saved search creation, maintenance, persisted matches, and match-feedback workflows.
- name: Watchlist
description: Watchlist membership, notification preferences, and watchlist-specific product state for authenticated users.
- name: Notifications
description: In-app notification retrieval, bulk updates, single-notification updates, and notification cleanup workflows.
- name: User Account
description:
Authenticated user profile management, admin user management, access-token lifecycle management, and partnership
listing.
- name: Billing
description: Stripe checkout, billing-portal, and subscription-management session creation for authenticated users.
- name: Newsletter
description: Newsletter subscription upsert workflows for website or product-surface sign-up flows.
- name: Partnerships
description: Partnership administration, safe summary reads, and membership/ListingSource count workflows.
- name: PartnershipApplications
description: Partnership application submission, review tracking, administration, and decision workflows.
- name: OAuth
description: OAuth 2.0 authorization, token, revocation, introspection, and OAuth client metadata management.