BLNG Journey API

REST API behind the BLNG Design application that manages design and shopping journeys, the prompts submitted against them, uploaded and generated image assets, chat prompts, design plans, and 3D model generation and conversion. Supports free-text search over journeys, cursor pagination via nextPageKey, and conditional GETs with ETag / If-None-Match. Authenticated with an AWS Cognito access or id token as a bearer JWT.

OpenAPI Specification

blng-journey-api-openapi.yml Raw ↑
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