openapi: 3.0.1
info:
  title: Carriyo Inventory API
  description: |-
    The Carriyo Inventory API manages stock levels across your fulfillment locations and tracks inventory changes over time. Submit inventory events to update per-location quantities, and query current balances by product or location.
  contact:
    name: Carriyo Support
    url: https://help.carriyo.com
    email: support@carriyo.com
  version: '1.0'
servers:
  - url: https://api.carriyo.com
    description: Production Server
  - url: https://demo-api.carriyo.com
    description: Demo Server
security:
  - OAuth2-Production: []
    ApiKey: []
    TenantId: []
  - OAuth2-Demo: []
    ApiKey: []
    TenantId: []
tags:
  - name: Inventory
    description: |-
      The Inventory resource provides a centralized view of stock levels across your fulfillment locations. Inventory records are automatically created and updated when you submit inventory events through the Inventory Events API.

      ## Key concepts

      ### Stock levels

      Inventory in Carriyo tracks three types of stock quantities for each product at each location:

      - **On hand**: total physical quantity of the product available at the location.
      - **Reserved**: quantity allocated to orders but not yet shipped.
      - **Unavailable**: quantity not available for sale (for example, damaged or expired).

      The **available quantity** is calculated as: `on_hand - reserved - unavailable`.

      ### Location-based tracking

      Inventory is tracked per product per location, allowing you to:
      - Monitor stock levels across multiple warehouses or stores
      - Allocate orders to locations with available inventory
      - Enable store-to-door or ship-from-store fulfillment

      ### Integration with orders

      When orders are created and allocated to fulfillment locations, Carriyo automatically reserves inventory. This ensures accurate available quantities are reflected in real-time.
  - name: Inventory Events
    description: |-
      Inventory events are the mechanism through which stock levels are updated in Carriyo. Instead of directly setting inventory quantities, you submit events that describe changes to your inventory.

      ## Event types

      The `event_type` field controls how the submitted quantities are applied. Each type is either a **Set** (overwrites the position to the absolute value you send) or an **Adjust** (applies a signed delta to the current position):

      | Event type | Write mode | Effect |
      |---|---|---|
      | `SNAPSHOT` | Set | Overwrites both `on_hand` and `unavailable` with the values you send. |
      | `SNAPSHOT_ONHAND` | Set | Overwrites `on_hand` only. |
      | `SNAPSHOT_UNAVAILABLE` | Set | Overwrites `unavailable` only. |
      | `INVENTORY_ADJUSTMENT_ONHAND` | Adjust | Applies a signed delta to `on_hand`. |
      | `INVENTORY_ADJUSTMENT_UNAVAILABLE` | Adjust | Applies a signed delta to `unavailable`. |
      | `RETURN` | Adjust | Records returned items as a delta to `unavailable`. |
      | `TRANSFER_IN` | Adjust | Records stock moved into the location as a delta. |
      | `TRANSFER_OUT` | Adjust | Records stock moved out of the location as a delta. |
      | `SALE` | Adjust | Records a sale as a delta (send a negative value to reduce stock). |
      | `PO_RECEIPT` | Adjust | Records a purchase-order receipt as a delta. |

      ## Bulk import

      The Inventory Events API supports bulk import, allowing you to submit multiple inventory events in a single request. This is useful for:

      - Syncing inventory from your ERP or WMS systems
      - Processing inventory adjustments in batch
      - Initial inventory setup

      Each bulk import request is identified by a unique `request_id` that you supply and can use to track the status of all events in the batch.

      ## Idempotency and retries

      The `request_id` you supply must be unique — re-using one is rejected (`requestId already exists`), so it guards against an accidental duplicate submission rather than acting as a replay token. Within a single batch you may submit at most one event per `product_id` and `location_id`.

      Whether a failed batch is safe to resubmit (under a new `request_id`) depends on the write mode:

      - **Set** events (`SNAPSHOT`, `SNAPSHOT_ONHAND`, `SNAPSHOT_UNAVAILABLE`) write an absolute position and are applied in `event_timestamp` order — a stale snapshot is ignored if a newer one has already been applied — so resubmitting the same values converges to the same result. Safe to retry.
      - **Adjust** events apply a signed delta, so resubmitting double-counts. If an adjust batch fails or times out, confirm whether it landed by retrieving the batch by its `request_id` before resubmitting.

      ## Event tracking

      Retrieve the status and results of inventory events using either:
      - **Request ID**: get all events from a specific bulk import.
      - **Product ID**: get all events for a specific product.

      This lets you verify that inventory updates were processed correctly and troubleshoot any failures.
paths:
  /inventory/product-id/{product-id}:
    get:
      tags:
        - Inventory
      summary: Get inventory by product ID
      operationId: get-inventory-by-product-id
      description: |-
        Retrieves the current inventory levels for a specific product across all locations.


        The response includes stock information for each location where the product has inventory,
        including:

        - **On Hand**: Total physical quantity available

        - **Reserved**: Quantity allocated to orders

        - **Unavailable**: Quantity not available for sale


        Use this endpoint to check real-time stock availability before allocating orders or to sync
        inventory data with external systems.
      parameters:
        - name: product-id
          in: path
          required: true
          schema:
            type: string
          description: The unique identifier of the product to retrieve inventory for.
      responses:
        '200':
          description: Successfully retrieved inventory for the product.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/inventory-response'
        '404':
          description: No inventory found for the specified product ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error-response'
      security:
        - OAuth2-Production: []
          ApiKey: []
          TenantId: []
        - OAuth2-Demo: []
          ApiKey: []
          TenantId: []
  /inventory/product-id/{product-id}/location-id/{location-id}:
    delete:
      tags:
        - Inventory
      summary: Delete inventory
      operationId: delete-inventory
      description: |-
        Permanently deletes the inventory record for a specific product at a specific location.


        **Warning**: This action cannot be undone. Use this endpoint when:

        - A product is discontinued at a location

        - Correcting data by removing incorrect inventory records

        - Cleaning up test data


        After deletion, the inventory for this product-location combination will need to be
        recreated through new inventory events.
      parameters:
        - name: product-id
          in: path
          required: true
          schema:
            type: string
          description: The unique identifier of the product.
        - name: location-id
          in: path
          required: true
          schema:
            type: string
          description: The unique identifier of the location.
      responses:
        '200':
          description: Successfully deleted the inventory record.
        '404':
          description: Inventory not found for the specified product and location.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error-response'
      security:
        - OAuth2-Production: []
          ApiKey: []
          TenantId: []
        - OAuth2-Demo: []
          ApiKey: []
          TenantId: []
  /inventory-events/request-id/{request-id}:
    get:
      tags:
        - Inventory Events
      summary: Get inventory events by request ID
      operationId: get-inventory-events-by-request-id
      description: |-
        Retrieves all inventory events that were submitted as part of a specific bulk import request.

        Use this endpoint to:
        - Verify that all events in a batch were processed successfully
        - Check the overall batch status (`COMPLETED` or `PROCESSING`)
        - Troubleshoot individual events

        ### Response shape

        The response includes:
        - `status`: Overall batch status
          - `COMPLETED` - All events have been processed
          - `PROCESSING` - Some events are still being processed
        - `inventory_events`: List of events sorted by sequence number
      parameters:
        - name: request-id
          in: path
          required: true
          schema:
            type: string
          description: The request ID returned from the bulk import operation.
      responses:
        '200':
          description: Successfully retrieved inventory events for the request.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/get-inventory-events-response'
        '404':
          description: No events found for the specified request ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error-response'
      security:
        - OAuth2-Production: []
          ApiKey: []
          TenantId: []
        - OAuth2-Demo: []
          ApiKey: []
          TenantId: []
  /inventory-events/product-id/{product-id}:
    get:
      tags:
        - Inventory Events
      summary: Get inventory events by product ID
      operationId: get-inventory-events-by-product-id
      description: |-
        Retrieves the history of inventory events for a specific product.


        Use this endpoint to:

        - Audit inventory changes over time

        - Debug unexpected inventory levels

        - Track the source and timing of inventory updates


        Events are returned in chronological order with full details including timestamps,
        quantities, and processing status.
      parameters:
        - name: product-id
          in: path
          required: true
          schema:
            type: string
          description: The unique identifier of the product to retrieve events for.
      responses:
        '200':
          description: Successfully retrieved inventory events for the product.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/inventory-event'
        '404':
          description: No events found for the specified product ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error-response'
      security:
        - OAuth2-Production: []
          ApiKey: []
          TenantId: []
        - OAuth2-Demo: []
          ApiKey: []
          TenantId: []
  /inventory-events/bulk/import:
    post:
      tags:
        - Inventory Events
      summary: Bulk import inventory events
      operationId: bulk-import-inventory-events
      description: |-
        Submits multiple inventory events in a single request to update stock levels across your locations.

        ### Request header requirements

        - `request-id` (required): a unique ID for this batch. Must not have been used before.

        ### Supported event types

        Only these event types are supported for bulk import:

        | Event type | Description | Required fields |
        |------------|-------------|-----------------|
        | `SNAPSHOT` | Set absolute values for both on_hand and unavailable | `on_hand` AND `unavailable` |
        | `SNAPSHOT_ONHAND` | Set absolute value for on_hand only | `on_hand` only |
        | `SNAPSHOT_UNAVAILABLE` | Set absolute value for unavailable only | `unavailable` only |
        | `INVENTORY_ADJUSTMENT_ONHAND` | Adjust on_hand by delta (+/-) | `on_hand` only |
        | `INVENTORY_ADJUSTMENT_UNAVAILABLE` | Adjust unavailable by delta (+/-) | `unavailable` only |
        | `RETURN` | Record returned items | `unavailable` only |
        | `TRANSFER_IN` | Record stock transfer into location | `on_hand` or `unavailable` |
        | `TRANSFER_OUT` | Record stock transfer out of location | `on_hand` or `unavailable` |
        | `SALE` | Record sales (usually negative adjustment) | `on_hand` or `unavailable` |
        | `PO_RECEIPT` | Record purchase order receipt | `on_hand` or `unavailable` |

        **Not supported** (internal events): `ORDER_RESERVATION`, `ORDER_UPDATE`, `ORDER_CANCELLATION`, `ORDER_FULFILLMENT`, `ORDER_UNFULFILLED`, `ORDER_RETURN`, `SHIPMENT_SHIPPED`.

        ### Validation rules

        - **Quantity range**: values must be between −1,000,000 and 1,000,000.
        - **Timestamp**: must be within the last 14 days and not in the future.
        - **No duplicates**: each `product_id` + `location_id` combination must be unique in the batch.
        - **Product/location**: must exist in your tenant.
        - **Location type**: must be an inventory-enabled location.

        ### Processing

        Events are processed asynchronously via a queue. The response indicates per event:
        - `PROCESSING`: event accepted and queued.
        - `REJECTED`: event failed validation, with a reason.

        ### Best practices

        - Use the `request-id` header to provide your own correlation ID.
        - Include `event_timestamp` to ensure events are processed in the correct order.
        - Check results for any `REJECTED` items.
      parameters:
        - name: request-id
          in: header
          required: true
          schema:
            type: string
          description: |-
            A unique request ID for this batch (required).
            - Must be unique across all previous requests
            - Use this to track processing status via the Get Events by Request ID endpoint
            - Cannot be reused - if you need to retry, use a new request ID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                $ref: '#/components/schemas/inventory-event-request'
      responses:
        '200':
          description: Successfully processed inventory events.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/inventory-event-bulk-response'
        '400':
          description: Invalid request payload.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/error-response'
      security:
        - OAuth2-Production: []
          ApiKey: []
          TenantId: []
        - OAuth2-Demo: []
          ApiKey: []
          TenantId: []
      x-codegen-request-body-name: body
components:
  schemas:
    error-response:
      title: Error Response
      type: object
      properties:
        error:
          type: string
          description: Error message describing what went wrong.
        code:
          type: string
          description: Error code for programmatic handling.
    inventory-response:
      title: Inventory Response
      type: object
      properties:
        tenant:
          type: string
          description: The tenant identifier.
        product_id:
          type: string
          description: The unique identifier of the product.
        stock_by_location:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/stock-info'
          description: Stock information keyed by location ID.
        creation_date:
          type: string
          format: date-time
          description: The date and time when the inventory record was created (ISO 8601 format).
        update_date:
          type: string
          format: date-time
          description: The date and time when the inventory record was last updated (ISO 8601 format).
        creation_source:
          $ref: '#/components/schemas/request-source'
        update_source:
          $ref: '#/components/schemas/request-source'
    stock-info:
      title: Stock Info
      type: object
      properties:
        on_hand:
          type: integer
          format: int64
          description: The total physical quantity available at the location.
        reserved:
          type: integer
          format: int64
          description: The quantity allocated to orders but not yet shipped.
        unavailable:
          type: integer
          format: int64
          description: The quantity not available for sale (damaged, expired, etc.).
        update_date:
          type: string
          format: date-time
          description: The date and time when the stock info was last updated.
        reservations:
          type: array
          items:
            $ref: '#/components/schemas/reservation'
          description: List of active reservations against this stock.
    reservation:
      title: Reservation
      type: object
      properties:
        order_id:
          type: string
          description: The order ID that created this reservation.
        reserved_quantity:
          type: integer
          format: int64
          description: The quantity reserved for this order.
        date:
          type: string
          format: date-time
          description: The date and time when the reservation was created.
    request-source:
      title: Request Source
      type: object
      properties:
        source:
          type: string
          description: The source system that made the request (e.g., API, UI, CONNECTOR).
        user_id:
          type: string
          description: The user or system identifier that made the request.
        ip_address:
          type: string
          description: The IP address from which the request originated.
    inventory-event-request:
      title: Inventory Event Request
      type: object
      required:
        - product_id
        - location_id
        - event_type
        - event_timestamp
      properties:
        product_id:
          type: string
          description: The unique identifier of the product. Must exist in your tenant.
        location_id:
          type: string
          description: The unique identifier of the location. Must be an inventory-enabled location.
        on_hand:
          type: integer
          format: int64
          minimum: -1000000
          maximum: 1000000
          description: |-
            The on-hand quantity value. Required for some event types:
            - Required: `SNAPSHOT`, `SNAPSHOT_ONHAND`, `INVENTORY_ADJUSTMENT_ONHAND`
            - Not allowed: `INVENTORY_ADJUSTMENT_UNAVAILABLE`, `RETURN`, `SNAPSHOT_UNAVAILABLE`
        unavailable:
          type: integer
          format: int64
          minimum: -1000000
          maximum: 1000000
          description: |-
            The unavailable quantity value. Required for some event types:

            - Required: `SNAPSHOT`, `SNAPSHOT_UNAVAILABLE`, `INVENTORY_ADJUSTMENT_UNAVAILABLE`,
            `RETURN`

            - Not allowed: `SNAPSHOT_ONHAND`, `INVENTORY_ADJUSTMENT_ONHAND`
        event_type:
          type: string
          enum:
            - SNAPSHOT
            - SNAPSHOT_ONHAND
            - SNAPSHOT_UNAVAILABLE
            - INVENTORY_ADJUSTMENT_ONHAND
            - INVENTORY_ADJUSTMENT_UNAVAILABLE
            - RETURN
            - TRANSFER_IN
            - TRANSFER_OUT
            - SALE
            - PO_RECEIPT
          description: |-
            The type of inventory event:
            - `SNAPSHOT` - Set absolute values for both on_hand and unavailable
            - `SNAPSHOT_ONHAND` - Set absolute value for on_hand only
            - `SNAPSHOT_UNAVAILABLE` - Set absolute value for unavailable only
            - `INVENTORY_ADJUSTMENT_ONHAND` - Adjust on_hand by delta (+/-)
            - `INVENTORY_ADJUSTMENT_UNAVAILABLE` - Adjust unavailable by delta (+/-)
            - `RETURN` - Record returned items (unavailable only)
            - `TRANSFER_IN` - Stock transfer into location
            - `TRANSFER_OUT` - Stock transfer out of location
            - `SALE` - Record sales
            - `PO_RECEIPT` - Purchase order receipt
        reason:
          type: string
          description: Optional reason or note for the inventory change.
        event_timestamp:
          type: string
          format: date-time
          description: |-
            The timestamp when the event occurred (ISO 8601 format). Required.
            - Must be within the last 14 days
            - Cannot be in the future
    inventory-event-bulk-response:
      title: Inventory Event Bulk Response
      type: object
      properties:
        request_id:
          type: string
          description: The unique identifier for this bulk import request. Use this to track event status.
        results:
          type: array
          items:
            $ref: '#/components/schemas/inventory-event-bulk-response-item'
          description: Processing results for each event in the request.
    inventory-event-bulk-response-item:
      title: Inventory Event Bulk Response Item
      type: object
      properties:
        product_id:
          type: string
          description: The product ID from the request.
        location_id:
          type: string
          description: The location ID from the request.
        result:
          type: string
          enum:
            - PROCESSING
            - REJECTED
          description: |-
            The processing result of this event:
            - `PROCESSING` - Event accepted and queued for processing
            - `REJECTED` - Event failed validation
        reason:
          type: string
          description: Reason for rejection if result is `REJECTED`.
    get-inventory-events-response:
      title: Get Inventory Events Response
      type: object
      properties:
        status:
          type: string
          enum:
            - COMPLETED
            - PROCESSING
          description: |-
            Overall status of the batch:
            - `COMPLETED` - All events in the batch have been processed
            - `PROCESSING` - Some events are still being processed
        inventory_events:
          type: array
          items:
            $ref: '#/components/schemas/inventory-event'
          description: List of inventory events for this request, sorted by sequence number.
    inventory-event:
      title: Inventory Event
      type: object
      properties:
        tenant:
          type: string
          description: The tenant identifier.
        product_id:
          type: string
          description: The unique identifier of the product.
        location_id:
          type: string
          description: The unique identifier of the location.
        request_id:
          type: string
          description: The request ID from the bulk import.
        event_type:
          type: string
          enum:
            - SNAPSHOT
            - SNAPSHOT_ONHAND
            - SNAPSHOT_UNAVAILABLE
            - INVENTORY_ADJUSTMENT_ONHAND
            - INVENTORY_ADJUSTMENT_UNAVAILABLE
            - ORDER_RESERVATION
            - ORDER_UPDATE
            - ORDER_CANCELLATION
            - ORDER_FULFILLMENT
            - ORDER_UNFULFILLED
            - ORDER_RETURN
            - SHIPMENT_SHIPPED
            - RETURN_REQUEST_REVERSE_SHIPMENT_DELIVERED
            - RETURN_REQUEST_MARKED_AS_RECEIVED
            - RETURN
            - TRANSFER_IN
            - TRANSFER_OUT
            - SALE
            - PO_RECEIPT
          description: The type of inventory event.
        on_hand:
          type: integer
          format: int64
          description: The on-hand quantity delta applied.
        reserved:
          type: integer
          format: int64
          description: The reserved quantity delta applied (for order-related events).
        unavailable:
          type: integer
          format: int64
          description: The unavailable quantity delta applied.
        status:
          type: string
          enum:
            - APPLIED
            - NOT_APPLIED
          description: Whether the event has been applied to the inventory snapshot. `NOT_APPLIED` events are typically superseded by a more recent `SNAPSHOT` event for the same product/location.
        error_message:
          type: string
          description: Error message explaining why the event was not applied. Populated when `status` is `NOT_APPLIED`.
        event_timestamp:
          type: string
          format: date-time
          description: The timestamp when the event occurred.
        receive_timestamp:
          type: string
          format: date-time
          description: Timestamp when Carriyo received the event for processing.
        creation_date:
          type: string
          format: date-time
          description: The timestamp when the event record was created.
        source:
          $ref: '#/components/schemas/request-source'
  securitySchemes:
    OAuth2-Production:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://api.carriyo.com/oauth/token
          scopes: {}
    OAuth2-Demo:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://demo-api.carriyo.com/oauth/token
          scopes: {}
    ApiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: "Your tenant's API key, issued in the Carriyo Dashboard. Required on every request except `POST /oauth/token`."
    TenantId:
      type: apiKey
      in: header
      name: tenant-id
      description: "Your Carriyo tenant ID, shown in the Carriyo Dashboard. Required on every request except `POST /oauth/token`."
