openapi: 3.0.3
info:
title: Journey API
description: API to manage user journeys in shopping or design domains,
including interactions like image uploads and prompt management.
version: 2.0.0
servers:
- url: /v2
paths:
/journeys:
get:
summary: Retrieve journeys or search for journeys based on criteria
operationId: getJourneys
tags:
- Journeys
parameters:
- name: userId
in: query
required: true
schema:
type: string
description: Unique identifier for the user whose journeys are being retrieved.
- name: type
in: query
schema:
type: string
enum:
- design
- shopping
description: Filter by the type of the journey.
- name: pageSize
in: query
required: false
schema:
type: integer
default: 10
maximum: 100
description: The number of journeys to return in a single page (default 10)
- name: nextPageKey
in: query
required: false
schema:
type: string
description: Token to retrieve the next set of journeys if paginating. Omit if
retrieving the first page.
- name: q
in: query
required: false
schema:
type: string
description: |
Free-text search term to fuzzy-match against the specified journey fields.
If provided, this routes through OpenSearch; otherwise DynamoDB paging is used.
- name: fields
in: query
required: false
style: form
explode: false
schema:
type: array
items:
type: string
enum:
- specifics.name
description: |
**Required** when `q` is present: comma-separated list of fields to fuzzy-search on.
Allowed values: [specifics.name].
- name: deleted
in: query
required: false
description: >-
When "true", returns only soft-deleted journeys (the recycle-bin
view) for the caller's workspace. Requires pageSize and cannot be
combined with q. Defaults to false (deleted journeys are excluded).
Because deleted journeys are filtered after the page limit is
applied, a page may contain fewer than pageSize items (or none)
while more remain; clients should keep paging until nextPageKey is
absent.
schema:
type: boolean
default: false
responses:
'200':
description: A list of journeys, optionally filtered based on query parameters.
Returns either a paginated response (when pageSize is provided) or
an array of journeys (when pageSize is not provided).
content:
application/json:
schema:
oneOf:
- type: object
description: Paginated response when pageSize parameter is provided
properties:
items:
type: array
items:
$ref: '#/components/schemas/Journey'
nextPageKey:
type: string
description: Token to retrieve the next page of journeys, or empty if no further
pages
totalCount:
type: number
description: >-
Total number of journeys matching the query, counted
across all DynamoDB pages (not just the first scan
window). Returned on the first page only and omitted
on subsequent pages (when a nextPageKey was supplied);
clients should retain the first page's value while
paging.
- type: array
description: Array of journeys when pageSize parameter is not provided (for
backward compatibility)
items:
$ref: '#/components/schemas/Journey'
'400':
description: Invalid request parameters
security:
- bearerAuth: []
- cognitoUserAuth: []
post:
summary: Start a new journey
operationId: startNewJourney
tags:
- Journeys
requestBody:
description: Data needed to initiate a new journey
required: true
content:
application/json:
schema:
type: object
required:
- userId
- type
properties:
userId:
type: string
description: Unique identifier for the user
type:
type: string
description: Type of the journey (design or shopping)
enum:
- design
- shopping
id:
type: string
description: Optional unique identifier for the journey. If not provided, the
server will generate one
responses:
'201':
description: Journey successfully created
content:
application/json:
schema:
$ref: '#/components/schemas/Journey'
'400':
description: Invalid input data
security:
- bearerAuth: []
- cognitoUserAuth: []
/journeys/versions:
get:
summary: Retrieve journeys by date since a specified timestamp
operationId: getJourneysByDate
tags:
- Journeys
parameters:
- name: userId
in: query
required: true
schema:
type: string
description: Unique identifier for the user whose journeys are being retrieved.
- name: since
in: query
required: true
schema:
type: string
format: ISO 8601 date-time
description: The starting date to filter journeys from, example -
2025-10-21T13:00:00Z.
responses:
'200':
description: A list of journeys created or updated since the specified date.
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Journey'
'400':
description: Invalid request parameters
/journeys/restore:
post:
summary: Restore multiple soft-deleted journeys in a single request
operationId: restoreJourneysBulk
tags:
- Journeys
requestBody:
description: List of journey IDs to restore (maximum 50 per request).
required: true
content:
application/json:
schema:
type: object
required:
- journeyIds
properties:
journeyIds:
type: array
minItems: 1
maxItems: 50
items:
type: string
description: Unique identifiers for the journeys to restore. Between 1 and 50
per request.
responses:
'200':
description: Per-journey restore outcomes. Always returns 200 for a valid
request; inspect each item's status for the outcome.
content:
application/json:
schema:
type: object
properties:
results:
type: array
items:
type: object
properties:
journeyId:
type: string
description: Unique identifier for the journey.
status:
type: string
enum:
- restored
- not_found
- forbidden
description: Outcome of the restore attempt for this journey.
'400':
description: Invalid request — journeyIds is missing, empty, contains a blank
id, exceeds 50 entries, or the body is not valid JSON.
security:
- bearerAuth: []
- cognitoUserAuth: []
/journeys/{journeyId}:
get:
summary: Retrieve a specific journey
operationId: getJourney
tags:
- Journeys
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
description: Unique identifier for the journey
- in: header
name: If-None-Match
description: |
If provided, the server returns `304 Not Modified` when the resource's
current `ETag` matches this value. Use the `ETag` returned from a prior
GET response as the value here for cheap revalidation.
required: false
schema:
type: string
example: 'W/"1714564800000-r3"'
responses:
'200':
description: Journey record returned in full.
headers:
ETag:
description: |
Weak entity tag for the returned journey, formatted as
`W/"<updatedAt-millis>-r<revision>"` (or `W/"<updatedAt-millis>"`
for legacy rows without a `revision` counter). Send this value
back as `If-None-Match` on subsequent GETs for cheap
revalidation.
schema:
type: string
example: 'W/"1714564800000-r3"'
Cache-Control:
description: |
Always `private, no-cache, must-revalidate`. Clients may cache
the body but MUST revalidate with the origin via
`If-None-Match` before reuse; per-user, so not cacheable by
shared intermediaries.
schema:
type: string
example: 'private, no-cache, must-revalidate'
content:
application/json:
schema:
$ref: '#/components/schemas/Journey'
'304':
description: |
Returned when the request's `If-None-Match` header matches the
current ETag. Body is empty; clients should reuse their cached
representation.
headers:
ETag:
description: |
Current ETag value, identical to the request's
`If-None-Match`.
schema:
type: string
example: 'W/"1714564800000-r3"'
Cache-Control:
description: Always `private, no-cache, must-revalidate`.
schema:
type: string
example: 'private, no-cache, must-revalidate'
'404':
description: Journey not found
security:
- bearerAuth: []
- cognitoUserAuth: []
delete:
summary: Delete a specific journey
description: >-
Soft-deletes (tombstones) a journey. Authorization follows the
container-ownership model: within a shared workspace, deletion is
governed by the caller's workspace role (OWNER/ADMIN/EDITOR may delete
any journey in the workspace, regardless of who created it;
BILLING_ADMIN and VIEWER may not), never by creatorship. Journeys
without a workspace context remain deletable only by their creator
(legacy).
operationId: deleteJourney
tags:
- Journeys
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
description: Unique identifier for the journey to be deleted
responses:
'204':
description: Journey successfully deleted
'403':
description: >-
Delete not permitted — the caller's workspace role does not allow
deletion, the caller is no longer a member of the journey's
workspace, or the role could not be verified.
'404':
description: Journey not found
security:
- bearerAuth: []
- cognitoUserAuth: []
/journeys/{journeyId}/restore:
post:
summary: Restore a soft-deleted journey
operationId: restoreJourney
tags:
- Journeys
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
description: Unique identifier for the journey to be restored
responses:
'200':
description: Journey successfully restored.
content:
application/json:
schema:
$ref: '#/components/schemas/Journey'
'403':
description: Restore not permitted — the caller is not the workspace owner, or
workspace ownership could not be verified (e.g. the journey has no
workspace context).
'404':
description: Journey not found, or not currently deleted.
security:
- bearerAuth: []
- cognitoUserAuth: []
/journeys/{journeyId}/prompts:
get:
summary: Retrieve paginated prompts for a specific journey, sorted from newest
to oldest.
operationId: getPromptsForJourney
tags:
- Prompts
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
description: Unique identifier for the journey
- name: pageSize
in: query
required: false
schema:
type: integer
default: 10
maximum: 100
description: The number of prompts to return in a single page (default 10)
- name: nextPageKey
in: query
required: false
schema:
type: string
description: Token to retrieve the next set of prompts if paginating. Null if no
more pages.
- name: includeLegacyPrompts
in: query
required: false
schema:
type: boolean
default: false
description: Include legacy prompts in the response. They are sorted oldest to
newest.
- in: header
name: If-None-Match
description: |
If provided, the server returns `304 Not Modified` when the
response body's current `ETag` matches this value. Use the
`ETag` returned from a prior GET response as the value here
for cheap revalidation. For paginated responses, send the
etag returned for page 1 (no `nextPageKey`) — newer prompts
and status changes always reflow page 1, so a page-1 304 is
a sound proxy for "the whole prompts list is unchanged".
required: false
schema:
type: string
example: 'W/"a1b2c3d4e5f60718"'
responses:
'200':
description: A paginated list of prompts
headers:
ETag:
description: |
Weak entity tag computed from a truncated SHA-256 hash
of the serialized response body. Send this value back
as `If-None-Match` on subsequent GETs for cheap
revalidation. Different pagination cursors produce
different etags.
schema:
type: string
example: 'W/"a1b2c3d4e5f60718"'
Cache-Control:
description: |
Always `private, no-cache, must-revalidate`. Clients may
cache the body but MUST revalidate with the origin via
`If-None-Match` before reuse; per-user, so not cacheable
by shared intermediaries.
schema:
type: string
example: 'private, no-cache, must-revalidate'
content:
application/json:
schema:
type: object
properties:
prompts:
type: array
items:
$ref: '#/components/schemas/Prompt'
legacyPrompts:
type: array
items:
$ref: '#/components/schemas/Prompt'
nextPageKey:
type: string
description: Token to retrieve the next page of prompts, or empty if no further
pages
'304':
description: |
Returned when the request's `If-None-Match` header matches
the current ETag. Body is empty; clients should reuse their
cached representation.
headers:
ETag:
description: Current ETag value, identical to the request's `If-None-Match`.
schema:
type: string
example: 'W/"a1b2c3d4e5f60718"'
Cache-Control:
description: Always `private, no-cache, must-revalidate`.
schema:
type: string
example: 'private, no-cache, must-revalidate'
'400':
description: Invalid request parameters
'404':
description: Journey or prompts not found
security:
- bearerAuth: []
- cognitoUserAuth: []
/journeys/{journeyId}/prompts/{promptId}:
get:
summary: Retrieve a single prompt by its unique identifier
operationId: getPromptById
tags:
- Prompts
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
description: Unique identifier for the journey
- name: promptId
in: path
required: true
schema:
type: string
description: Unique identifier for the prompt
- name: includeLegacyPrompts
in: query
required: false
schema:
type: boolean
default: false
description: If true, includes legacy prompt details from the journey in the
response
responses:
'200':
description: Details of the requested prompt
content:
application/json:
schema:
type: object
properties:
prompt:
$ref: '#/components/schemas/Prompt'
'400':
description: Invalid request parameters
'404':
description: Prompt not found
security:
- bearerAuth: []
- cognitoUserAuth: []
/journeys/{journeyId}/prompts/{promptId}/cancel-processing:
post:
summary: Cancel design-v3 prompt processing before a plan exists
description: |
Marks the prompt as pipeline-cancelled and completed so the user can submit a new prompt.
Once `response.planId` exists, use `POST .../plans/{planId}/cancel` instead.
operationId: cancelPromptProcessingBeforePlan
tags:
- Prompts
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
- name: promptId
in: path
required: true
schema:
type: string
responses:
'200':
description: Updated prompt
content:
application/json:
schema:
$ref: '#/components/schemas/Prompt'
'400':
description: Invalid request (e.g. not design-v3)
'404':
description: Journey or prompt not found
'409':
description: Conflict — plan already exists or prompt already terminal
security:
- bearerAuth: []
- cognitoUserAuth: []
/journeys/{journeyId}/prompts/{promptId}/plans/{planId}/cancel:
post:
summary: Cancel a design plan for a prompt in a journey
operationId: cancelDesignPlanForPromptInJourney
tags:
- Prompts
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
- name: promptId
in: path
required: true
schema:
type: string
- name: planId
in: path
required: true
schema:
type: string
responses:
'200':
description: Design plans
content:
application/json:
schema:
type: object
properties:
'422':
description: Validation Error
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/assets:
get:
summary: List assets for the authenticated user (newest first)
operationId: listAssetsForUser
tags:
- Design Journey
- Assets
parameters:
- name: pageSize
in: query
schema:
type: integer
default: 10
maximum: 100
- name: nextPageKey
in: query
schema:
type: string
responses:
'200':
description: Assets
content:
application/json:
schema:
type: object
properties:
items:
type: array
items:
$ref: '#/components/schemas/Asset'
nextPageKey:
type: string
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/assets/upload:
post:
summary: Create an upload slot and return a pre-signed URL
operationId: createAssetUploadUrl
tags:
- Design Journey
- Assets
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- type
- contentType
properties:
type:
type: string
description: Asset category
enum:
- image
- model
- stamps
contentType:
type: string
description: >
MIME type that must be sent in the upload; baked into the
presign. Externalized CRDT stamp blobs (type=stamps) use
application/octet-stream.
format:
type: string
description: Optional hint (e.g., glb, usdz, png). Server will infer/validate.
id:
type: string
description: Optional asset ID to use for the new asset placeholder. If not
provided, the server will generate one
responses:
'201':
description: Upload URL and asset id
content:
application/json:
schema:
type: object
properties:
url:
type: string
description: Pre-signed URL for uploading the asset
id:
type: string
description: ID of the new asset placeholder
'400':
description: Invalid input (unsupported type/contentType/format or mismatch)
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/assets/{assetId}:
get:
summary: Get asset metadata
operationId: getAsset
tags:
- Design Journey
- Assets
parameters:
- name: assetId
in: path
required: true
schema:
type: string
responses:
'200':
description: Asset metadata
content:
application/json:
schema:
$ref: '#/components/schemas/Asset'
'404':
description: Asset not found
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/assets/{assetId}/download:
get:
summary: Get a signed URL for downloading an asset
operationId: getAssetDownloadUrl
tags:
- Design Journey
- Assets
parameters:
- name: assetId
in: path
required: true
schema:
type: string
- name: variant
in: query
required: false
description: >
Which object to sign. Omit for the asset itself; use `thumbnail` to
sign the video's thumbnail/preview still (only valid when the asset
has a thumbnail).
schema:
type: string
enum: [ thumbnail ]
responses:
'200':
description: Time-limited download URL
content:
application/json:
schema:
type: object
properties:
url:
type: string
description: Pre-signed URL for downloading the asset
'404':
description: Asset not found
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/journeys/{journeyId}/images/upload:
post:
deprecated: true
summary: Generate an image and get a pre-signed URL for upload
operationId: generateImageUploadURL
tags:
- Design Journey
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
contentType:
type: string
description: The MIME type of the file to be uploaded.
enum:
- image/jpeg
- image/jpg
- image/png
- image/gif
example: image/jpeg
id:
type: string
description: Optional image ID to use for the new image placeholder. If not
provided, the server will generate one
responses:
'201':
description: Pre-signed URL for image upload and image ID
content:
application/json:
schema:
type: object
properties:
url:
type: string
description: Pre-signed URL for uploading the image.
imageId:
type: string
description: Unique identifier for the newly created image placeholder.
'400':
description: Invalid content type provided
'404':
description: Journey not found
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/journeys/{journeyId}/images:
get:
deprecated: true
summary: Retrieve all images for a journey
operationId: getAllImagesForJourney
tags:
- Design Journey
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
responses:
'200':
description: List of images associated with the journey
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Image'
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/journeys/{journeyId}/images/{imageId}:
get:
deprecated: true
summary: Retrieve metadata for a specified image
operationId: getImageMetadata
tags:
- Design Journey
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
- name: imageId
in: path
required: true
schema:
type: string
responses:
'200':
description: Image metadata retrieved successfully
content:
application/json:
schema:
$ref: '#/components/schemas/Image'
security:
- bearerAuth: []
- cognitoUserAuth: []
delete:
deprecated: true
summary: Remove a specific image from the journey
operationId: deleteImage
tags:
- Design Journey
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
- name: imageId
in: path
required: true
schema:
type: string
responses:
'204':
description: Image successfully deleted
'404':
description: Image not found
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/journeys/{journeyId}/images/{imageId}/download:
get:
deprecated: true
summary: Generate a pre-signed URL for downloading an image
operationId: generateImageDownloadUrl
tags:
- Design Journey
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
- name: imageId
in: path
required: true
schema:
type: string
responses:
'200':
description: Pre-signed URL generated for image download
content:
application/json:
schema:
type: object
properties:
url:
type: string
description: Pre-signed URL for downloading the image.
'404':
description: Image not found
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/journeys/{journeyId}/chat-prompt:
post:
summary: Submit a chat prompt request (design-v2)
operationId: submitChatPrompt
tags:
- Chat Prompts
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ChatPromptRequest'
responses:
'200':
description: Chat prompt successfully processed
content:
application/json:
schema:
$ref: '#/components/schemas/ChatPrompt'
'400':
description: Invalid input data
'429':
description: Too many requests, the user has exceeded their concurrency limit
content:
application/json:
schema:
type: object
properties:
code: { type: string, example: 'CONCURRENCY_LIMIT_EXCEEDED' }
message:
{
type: string,
example: 'User has exceeded their concurrency limit for chat prompts'
}
security:
- bearerAuth: []
- cognitoUserAuth: []
/design/journeys/{journeyId}/chat-prompt-v3:
post:
summary: Submit a chat prompt request (design-v3)
operationId: submitChatPromptV3
tags:
- Chat Prompts
parameters:
- name: journeyId
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ChatPromptRequestV3'
responses:
'200':
description: Chat prompt successfully processed
content:
application/json:
schema:
$ref: '#/components/schemas/ChatPrompt'
'400':
description: Invalid input data
'429':
description: Too many requests, the user has exceeded their concu
# --- truncated at 32 KB (81 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/blng/refs/heads/main/openapi/blng-journey-api-openapi.yml