Ankorstore Stock Tracking and Logistics API (ASTRAL)

Advanced stock and inventory visibility beyond the core Catalog endpoints: query stock state by product variant, location and status; view stock movement postings and transactions; and list stock locations, with lot-level detail.

OpenAPI Specification

ankorstore-astral-openapi-original.yml Raw ↑
openapi: 3.1.0
info:
  version: 1.2.2-oas3.1
  title: Ankorstore Stock Tracking and Logistics API
  summary: API specification for the Ankorstore Stock Tracking and Logistics system
  description: Ankorstore Stock Tracking and Logistics (ASTRAL) API specification
  contact:
    name: Ankorstore
    url: https://www.ankorstore.com
    email: api@ankorstore.com
  license:
    url: https://creativecommons.org/publicdomain/zero/1.0/
    name: CC0 1.0 Universal
servers:
  - url: http://www.ankorlocal.com:8000
    description: Local Development Server
  - url: https://www.preprod.ankorstore.com
    description: Staging Environment
  - url: https://www.ankorstore.com
    description: Prod Environment
paths:
  /api/astral/v1/stock/state:
    get:
      tags:
        - State
      summary: Stock quantities by location and status
      description: |
        Return the current quantity for a given product variant across locations, statuses and potentially lots.
        One stock state entity is returned per product variant, so the identifier of each entity will correspond with
        the product variant identifier for which quantities are returned.
      operationId: list-state
      parameters:
        - $ref: '#/components/parameters/acceptInHeader'
        - $ref: '#/components/parameters/xAksBrandUuidHeader'
        - $ref: '#/components/parameters/xAksRetailerUuidHeader'
        - $ref: '#/components/parameters/productVariantIdFilter'
        - $ref: '#/components/parameters/statusFilter'
        - $ref: '#/components/parameters/locationTypeFilter'
        - $ref: '#/components/parameters/locationIdFilter'
        - $ref: '#/components/parameters/productTypeFilter'
        - $ref: '#/components/parameters/pageLimit'
        - $ref: '#/components/parameters/pageBefore'
        - $ref: '#/components/parameters/pageAfter'
        - $ref: '#/components/parameters/stateAt'
      responses:
        default: {$ref: "#/components/responses/ErrorResponse"}
        "200": {$ref: "#/components/responses/StockStateCollectionResponse"}
    patch:
      tags:
        - State
      summary: Update stock state
      description: |
        Override the stock state for one or more product variants.
        * Only brand locations and available or onHand statuses are available for update.
        * You may only specify either onHand or available for the same product variant and location, not both.
        * Please include only absolute quantities.
      operationId: patch-state
      parameters:
        - $ref: '#/components/parameters/acceptInHeader'
        - $ref: '#/components/parameters/xAksBrandUuidHeader'
        - $ref: '#/components/parameters/xAksRetailerUuidHeader'
      requestBody: {$ref: '#/components/requestBodies/StockStateRequest'}
      responses:
        default: {$ref: "#/components/responses/ErrorResponse"}
        "204": {$ref: "#/components/responses/NoContent"}
  /api/astral/v1/stock/postings:
    get:
      tags:
        - Movements
      summary: List postings
      description: |
        Returns movement history for a set of product variants and locations, based on the provided filters.
        To receive information on which specific lots were involved in the movement, include the `lot` resource. You
        may also include the transaction resource to get more information on what caused the posting.
      operationId: list-postings
      parameters:
        - $ref: '#/components/parameters/acceptInHeader'
        - $ref: '#/components/parameters/xAksBrandUuidHeader'
        - $ref: '#/components/parameters/xAksRetailerUuidHeader'
        - $ref: '#/components/parameters/productVariantIdFilter'
        - $ref: '#/components/parameters/locationTypeFilter'
        - $ref: '#/components/parameters/locationIdFilter'
        - $ref: '#/components/parameters/locationStatusFilter'
        - $ref: '#/components/parameters/pageLimit'
        - $ref: '#/components/parameters/pageBeforeUuidTimestamp'
        - $ref: '#/components/parameters/pageAfterUuidTimestamp'
        - name: sort
          in: query
          description: Specify what to sort by
          required: false
          allowEmptyValue: false
          schema:
            type: string
            enum:
              - transaction.createdAt
              - '-transaction.createdAt'
        - name: filter[movementType][in][]
          in: query
          description: Include only specific movement types
          required: false
          schema:
            type: array
            items: {$ref: '#/components/schemas/MovementType'}
        - name: filter[movementType][notIn][]
          in: query
          description: Exclude specific movement types
          required: false
          schema:
            type: array
            items: {$ref: '#/components/schemas/MovementType'}
        - name: include
          in: query
          description: >-
            A comma-separated list of resources to include. Options are transaction, lot, state. The states that will be included represent the quantities at the start of the set of postings. Eg. when sorted ascending, the state will represent the quantities at cursor `meta.page.from`. When sorting descending, `meta.page.to`
          schema:
            type: string
      responses:
        default: {$ref: "#/components/responses/ErrorResponse"}
        "200": {$ref: "#/components/responses/PostingCollectionResponse"}
  /api/astral/v1/stock/transactions:
    get:
      tags:
        - Movements
      summary: List transactions
      description: |
        Returns transaction history for a set of product variants and locations, based on the provided filters.
        Filters include relatedId, which is typically filled with the masterOrderUuid, fulfillmentOrderUuid or in case
        of reservations, a user-specified identifier. You may also include the posting resource to get the individual
        postings contained within the transaction(s).
      operationId: list-transactions
      parameters:
        - $ref: '#/components/parameters/acceptInHeader'
        - $ref: '#/components/parameters/xAksBrandUuidHeader'
        - $ref: '#/components/parameters/xAksRetailerUuidHeader'
        - $ref: '#/components/parameters/productVariantIdFilter'
        - $ref: '#/components/parameters/locationTypeFilter'
        - $ref: '#/components/parameters/locationIdFilter'
        - $ref: '#/components/parameters/locationStatusFilter'
        - $ref: '#/components/parameters/pageLimit'
        - $ref: '#/components/parameters/pageBeforeUuidTimestamp'
        - $ref: '#/components/parameters/pageAfterUuidTimestamp'
        - name: filter[relatedIds][]
          in: query
          description: A set of related identifiers to fetch transactions for
          required: false
          schema:
            type: array
            minItems: 1
            items:
              type: string
        - name: sort
          in: query
          description: Specify what to sort by
          required: false
          allowEmptyValue: false
          schema:
            type: string
            enum:
              - createdAt
              - '-createdAt'
        - name: include
          in: query
          description: 'A comma-separated list of resources to include. Options are: posting'
          schema:
            type: string
      responses:
        default: {$ref: "#/components/responses/ErrorResponse"}
        "200": {$ref: "#/components/responses/TransactionCollectionResponse"}
  /api/astral/v1/stock/locations:
    get:
      tags:
        - Locations
      summary: List locations
      description: Return the list of available locations
      operationId: list-locations
      parameters:
        - $ref: '#/components/parameters/acceptInHeader'
        - $ref: '#/components/parameters/xAksBrandUuidHeader'
        - $ref: '#/components/parameters/xAksRetailerUuidHeader'
        - $ref: '#/components/parameters/locationTypeFilter'
        - $ref: '#/components/parameters/externalIdFilter'
        - $ref: '#/components/parameters/pageLimit'
        - $ref: '#/components/parameters/pageBefore'
        - $ref: '#/components/parameters/pageAfter'
      responses:
        default: {$ref: "#/components/responses/ErrorResponse"}
        "200": {$ref: "#/components/responses/LocationCollectionResponse"}
tags:
  - name: How to work with the Ankorstore Stock Tracking and Logistics API
    description: "ℹ️ This section provides an overview of the general concepts and conventions used throughout the API.\n\n### API Specification\nThis API follows the [Ankorstore API Specification](https://api-spec.ankorstore.com) which is based on the [JSON:API](https://jsonapi.org/) specification.\n\n### Headers\nWhen making any request, the header `Accept: application/vnd.api+json` is required.\nWhen sending JSON within the body of a request the header `Content-Type: application/vnd.api+json` is also required.\n\n\U0001F517 [Learn more about JSON:API media types](https://jsonapi.org/format/#jsonapi-media-type)\n\n### Resource Data\nIn every response, the actual resource data can be found in the root level object `data`, this will either be an array\nor an object, depending on if its list based or not.\n\n\U0001F517 [Learn more about JSON:API document structure](https://jsonapi.org/format/#document-structure)\n\n### Includes\nResources may have the ability to include data from other relations in the same request.\nFor example, when fetching a single posting you may include the related transaction and lots\n\n`?include=transaction,lots`\n\n<div class=\"info\">\n\n### Pagination\nAnkorstore uses cursor based pagination. In the root level object for pagination supported endpoints\nyou will find a `meta` object containing pagination information:\n\n```yaml json_schema\n  type: object\n  description: Meta\n  properties:\n    meta:\n      type: object\n      description: Meta with Pagination Details\n      properties:\n        page:\n          description: Cursor pagination details\n          type: object\n          properties:\n            from:\n              type: string\n            to:\n              type: string\n            hasMore:\n              type: boolean\n            perPage:\n              type: integer\n```\n\nAs an example:\n\n```json\n{\n  \"meta\": {\n    \"page\": {\n      \"from\": \"63e9bacd-0288-4cf1-81ab-b34270c7f68a\",\n      \"to\": \"747a1dcd-decc-4f8d-a9a9-61ff4d33d92e\",\n      \"hasMore\": true,\n      \"perPage\": 15\n    }\n  }\n}\n```\n\nYou may manually construct the pagination query parameters yourself using `page[limit]` with `page[before]`\nor `page[after]` depending on which direction you wish to iterate over.\n\n<div class=\"info\">\n\n#### Effective pagination\n\nWe recommend using the provided helper pagination links below instead of manually constructing the URLs yourself.\n\n</div>\n\nThe response will also provide pagination links, so you do not need to construct these yourself:\n\n```yaml json_schema\n  type: object\n  description: Links\n  properties:\n    links:\n      description: Pagination navigation links. If a link does not exist then you cannot paginate any further in that direction.\n      type: object\n      properties:\n        first:\n          type: string\n          format: url\n        next:\n          type: string\n          format: url\n        prev:\n          type: string\n          format: url\n```\n\nAs an example:\n\n```json\n{\n  \"links\": {\n    \"first\": \"https://www.ankorstore.com/api/astral/v1/postings?page%5Blimit%5D=15\",\n    \"next\": \"https://www.ankorstore.com/api/astral/v1/postings?page%5Bafter%5D=1189606a-139e-4b4e-917c-b0c992498bad&page%5Blimit%5D=15\",\n    \"prev\": \"https://www.ankorstore.com/api/astral/v1/postings?page%5Bbefore%5D=e04e17bb-9e70-4ecd-a8f5-4417d45b872c&page%5Blimit%5D=15\"\n  }\n}\n```\n\n\U0001F517 [Learn more about JSON:API pagination](https://jsonapi.org/format/#fetching-pagination)\n\n### Filters\n\nAn endpoint that supports filters requires each listed filter to be wrapped in a filter object.\nE.g. you may wish to only retrieve stock quantities for a given status:\n\n`?filter[status][]=available`\n\nYou may chain filters as well:\n\n`?filter[status][]=available&filter[locationIds][]=1189606a-572e-4b4e-88da-b0c992498bad`\n\n<div class=\"info\">\n\n#### What filters can be used?\n\nThe supported filters will be listed on each endpoint in the API documentation.\n\n</div>\n\n\U0001F517 [Learn more about JSON:API filters](https://jsonapi.org/format/#fetching-filtering)"
  - name: Authentication
    description: |+
      ℹ️ The Ankorstore API uses OAuth2 authentication, in order to get a `client_id` and a `client_secret` please,
      login at https://www.ankorstore.com/ and generate a new application
      in the [integrations](https://ankorstore.com/account/integrations) area of your account.

      To generate a token pass in your `client_id` and `client_secret`:

      ```json http
      {
        "method": "post",
        "headers": {
          "accept": "application/json",
          "Content-Type": "application/x-www-form-urlencoded"
        },
        "baseUrl": "https://www.ankorstore.com",
        "url": "/oauth/token",
        "body": "grant_type=client_credentials&client_id={{client_id}}&client_secret={{client_secret}}&scope=*"
      }
      ```

      You will receive an `access_token`:

      ```json
      {
        "token_type": "Bearer",
        "expires_in": 3600,
        "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9<...>"
      }
      ```

      This access token has an expiry, in which you will receive an `401 Unauthenticated` response. To generate a new one
      you can re-call the `/oauth/token` endpoint described above.

      To authenticate with every other endpoint pass in the header `Authorization: Bearer {token}`.
      You can test if your token is working with this endpoint (this is a not a JSON:API based endpoint):

      ```json http
      {
        "method": "get",
        "headers": {
          "accept": "application/json",
          "Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9<...>"
        },
        "baseUrl": "https://www.ankorstore.com",
        "url": "/api/v1/me"
      }
      ```

      If successful you will receive a 200 response:

      ```json
      {
        "data": {
          "type": "user",
          "id": 1234,
          "email": "api@ankorstore.com",
          "first_name": "Test",
          "last_name": "Account",
          "created_at": "2020-01-28T11:26:35+00:00",
          "updated_at": "2022-03-15T15:23:09+00:00"
        }
      }
      ```

  - name: Stock Concepts
    description: |-
      ℹ️ This section defines the various concepts and entities used in the API.

      ### Product variants
      Product variants are entities that can be sold via the Ankorstore Marketplace and/or fulfilled via Ankorstore logistics.
      They are the primary entity that other systems can use to interact with the stock API

      ### Batches & Units
      Batches represent a physically pickable entity, used as the indivisible quantity for all matters stock tracking.
      Unless specified otherwise, any quantity in the ASTRAL API will be the number of batches.

      Units describe how many individual units are contained within a batch. It may be used for informational purposes
      by the marketplace, but all stock movement tracking is primarily done with batches.

      ### Bundles
      A product variant may be composed of several other product variants. These are called bundles. Within a bundle, each
      product variant contained will have a multiplier to indicate how many batches are contained within the bundle.

      When stock for a bundle is reserved, the stock of each individual product variant contained within the bundle is
      decremented accordingly.

      ### Lots
      A lots refers to a specific quantity of items that are produced, stored, or shipped together and identified with
      a lot number. An item may have many lots, and each lot is uniquely identified by a lot number + an optional expiry date.

      When reserving stock, you may specify a lot number and expiry date to obtain stock from that specific lot.
      If you do not specify a lot number, and the item has lots attached, the system will automatically select the lot
      with the earliest expiry date.

      ## Movements
      Ankorstore maintains a double-entry ledger for stock tracking, meaning that for each stock change on a target there
      must be an equal and opposite entry on the source.

      Movements may be between physical locations, such as a warehouse and retailer, or between virtual stock statuses,
      such as available and reserved.

      ### Postings
      Each single stock quantity change on a specific location and status is represented as a Posting, with a movementType
      to describe the reason of the change. Postings are considered immutable, forming an accounting-equivalent record of
      the full stock history.

      ### Transactions
      Transactions represent a single trigger or event that initiated a set of stock changes, and group together a set of
      postings with a timestamp, external identifiers and potentially metadata. Examples include a order reservation,
      order shipment, or location snapshot

      ## Stock state
      A stock state represents the current "balance", the quantity for a given product variant across locations, statuses
      and potentially lots. It may show for example, how many batches are currently `available` at a given `warehouse`
      for each lot of a `product variant` X.

      Stock state is always grouped per product variant, so the identifier for stock-state entities corresponds with the
      product variant ID for which quantities are shown.

      ### Location & Stock statuses
      Ankorstore maintains 2 concepts of status; location status represents a physical or virtual ledger of stock, while
      stock status represents a status for which a balance can be maintained.

      A stock status may be a super-set of location status, such as onHand, which is the super-set of available, reserved
      blocked, damaged and qualityControl. Conversely, some location statuses may be tracked without being exposed
      as stock status

      | State          | Description                                                                                                                                            | Location status | Stock status |   |
      |----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------|--------------|---|
      | available      | Inventory that is considered available for orders or fulfillment                                                                                       | yes             | yes          |   |
      | onHand         | Inventory that is present at a location. This is a sum of available, reserved, damaged, qualityControl and blocked                                     | no              | yes          |   |
      | reserved       | Inventory that are set aside, and currently not available for orders or fulfillment                                                                    | yes             | yes          |   |
      | damaged        | Inventory that is damaged, and thus no longer available for orders or fulfillment                                                                      | yes             | yes          |   |
      | qualityControl | Inventory that is set aside for inspection, and thus no longer available for orders or fulfillment                                                     | yes             | yes          |   |
      | blocked        | Inventory that is blocked for any reason other than damage or inspection, and thus no longer available for orders or fulfillment. For example: expired | yes             | yes          |   |
      | incoming       | Inventory that is expected but not yet physically present at the location                                                                              | yes             | yes          |   |
      | void           | Wildcard location to source (temporarily) unexplained movements to and from                                                                            | yes             | no            |   |

      ## Reservations
      Reservations are a specific type of transaction that represent a temporary allocation of stock. A reservation may only
      be created when the stock balances in status `available` is higher than the requested quantities, and will move the
      requested quantities of stock from the `available` status to the `reserved` status within the same location.



      ### Postings
      Postings are always linked to items, and each item must be linked to at least one "single" product variant. So the
      Postings endpoint will return movements for "single" product variants only. If a bundle is specified, movements
      should be returned for all single product variants contained within the bundle.

      ### Stock state
      Stock states can represent either a single product variant or a bundle. If a bundle is specified, the quantities
      in the stock state should be computed as the largest possible common denominator of the contained single product
      variants.

      Example: consider a bundle BX containing `10 x PY` + `5 x PZ`, with the stock state for A being `30` and B being `10`.
      Then the stock state for BX will be `2`, as PZ `10 / 5 = 2` defines the available number of complete bundles.
  - name: State
  - name: Reservations
  - name: Locations
  - name: Movements
components:
  requestBodies:
    StockReservationRequest:
      content:
        application/vnd.api+json:
          schema:
            type: object
            properties:
              data: {$ref: '#/components/schemas/StockReservation'}
            required:
              - data
          examples:
            example-create-order-reservation:
              value:
                data:
                  type: reservation
                  id: 1ed86ab7-c16e-6002-b4d0-0242ac15000c
                  attributes:
                    items:
                      - productVariantId: 0f358c35-9698-46f4-8856-d0441e0533e5
                        quantity: 10
                        locationId: 0fba0067-87cb-4e36-9885-2529eb0475cc
                      - productVariantId: 0f358c35-9698-46f4-8856-d0441e0533e5
                        quantity: 5
                        locationId: 0fba0067-87cb-4e36-9885-2529eb0475cc
                        lotNumber: lot-abc
                    relatedId: 7326952d-383a-496b-ad8c-63a2517c0dbd
                    metadata:
                      masterOrderId: 7326952d-383a-496b-ad8c-63a2517c0dbd
    LocationRequest:
      content:
        application/vnd.api+json:
          schema:
            type: object
            properties:
              data: {$ref: '#/components/schemas/LocationResource'}
            required:
              - data
          examples:
            example-create-location:
              value:
                data:
                  type: location
                  id: 38cbe75a-9e3c-4adc-a465-351625a88c3f
                  attributes:
                    externalId: 1841c9e9-33cc-4fd5-8045-32654adcc78a
                    type: warehouse
    StockStateRequest:
      content:
        application/vnd.api+json:
          schema:
            type: object
            properties:
              data:
                type: array
                items: {$ref: '#/components/schemas/ProductVariantStockStateResource'}
            required:
              - data
          examples:
            example-change-stock-state:
              value:
                data:
                  - type: 'stock-state'
                    id: 1ed86ab7-c16e-6002-b4d0-0242ac15000c
                    attributes:
                      quantities:
                        - quantity: 10
                          locationId: '3fa85f64-5717-4562-b3fc-2c963f66afa6'
                          status: 'available'
                  - type: 'stock-state'
                    id: 1841c9e9-33cc-4fd5-8045-32654adcc78a
                    attributes:
                      quantities:
                        - quantity: 80
                          locationId: '3fa85f64-5717-4562-b3fc-2c963f66afa6'
                          status: 'onHand'
  securitySchemes:
    CookieKey:
      type: apiKey
      name: ankorstore_session
      in: cookie
  responses:
    NoContent: # 201
      description: No content
    ErrorResponse:
      description: Example response
      content:
        application/vnd.api+json:
          schema:
            type: object
            properties:
              errors:
                type: array
                items: {$ref: '#/components/schemas/Error'}
              jsonapi: {$ref: '#/components/schemas/jsonapi'}
            required:
              - errors
    StockStateCollectionResponse:
      description: Set of stock state records
      content:
        application/vnd.api+json:
          schema:
            type: object
            properties:
              data:
                type: array
                items: {$ref: '#/components/schemas/ProductVariantStockStateResource'}
              jsonapi: {$ref: '#/components/schemas/jsonapi'}
              meta: {$ref: '#/components/schemas/paginationMeta'}
              links: {$ref: '#/components/schemas/paginationLinks'}
            required:
              - data
              - jsonapi
          examples:
            example-get-stock-quantities:
              value:
                data:
                  - type: 'stock-state'
                    id: 1ed86ab7-c16e-6002-b4d0-0242ac15000c
                    attributes:
                      quantities:
                        - quantity: 10
                          locationId: 3fa85f64-5717-4562-b3fc-2c963f66afa6
                          locationType: warehouse
                          status: 'available'
                          lot:
                            lotNumber: 'lot-20240915-a'
                            expiryDate: "2024-09-15"
                        - quantity: 7
                          locationId: 0f358c35-9698-46f4-8856-d0441e0533e5
                          locationType: warehouse
                          status: 'reserved'
                          lot:
                            lotNumber: 'lot-20240915-a'
                            expiryDate: "2024-09-15"
                        - quantity: 3
                          locationId: 0f358c35-9698-46f4-8856-d0441e0533e5
                          locationType: warehouse
                          status: 'reserved'
                        - quantity: 2
                          locationId: 0f358c35-9698-46f4-8856-d0441e0533e5
                          locationType: warehouse
                          status: 'blocked'
                          lot:
                            lotNumber: 'lot-20231215-x'
                            expiryDate: "2023-12-15"
                  - type: 'stock-state'
                    id: 018fc37c-d9bc-7a25-96e0-9c80c843b6ea
                    attributes:
                      quantities:
                        - quantity: 5
                          locationId: 018fc37e-4460-7b27-8151-ee7422b71f2e
                          locationType: warehouse
                          status: 'incoming'
                          lot:
                            lotNumber: 'lot-without-expiry'
                        - quantity: 7
                          locationId: 0f358c35-9698-46f4-8856-d0441e0533e5
                          locationType: warehouse
                          status: 'available'
                          lot:
                            lotNumber: 'lot-without-expiry'
                jsonapi:
                  version: string
                  meta: {}
    LocationCollectionResponse:
      description: Set of locations
      content:
        application/vnd.api+json:
          schema:
            type: object
            properties:
              data:
                type: array
                items: {$ref: '#/components/schemas/LocationResource'}
              jsonapi: {$ref: '#/components/schemas/jsonapi'}
              meta: {$ref: '#/components/schemas/paginationMeta'}
              links: {$ref: '#/components/schemas/paginationLinks'}
            required:
              - data
              - jsonapi
    LocationResponse:
      description: A single location
      content:
        application/vnd.api+json:
          schema:
            type: object
            properties:
              data: {$ref: '#/components/schemas/LocationResource'}
              jsonapi: {$ref: '#/components/schemas/jsonapi'}
            required:
              - data
              - jsonapi
    PostingCollectionResponse:
      description: Set of postings
      content:
        application/vnd.api+json:
          schema: {$ref: '#/components/schemas/PostingCollection'}
          examples:
            example-get-postings-simple:
              value:
                data:
                  - type: 'posting'
                    id: 018fc37f-5c0a-7913-a672-9569d7b48756
                    attributes:
                      locationId: 20e62581-67a5-4166-8b1f-344e9b06b58b
                      productVariantId: 018fc380-1c43-75f9-a101-49447fbadeb7
                      locationStatus: available
                      movementType: 'order_reserved'
                      quantity: -10
                      unitMultiplier: 1
                  - type: 'posting'
                    id: 018fc385-5d99-7305-9cf5-a18b40005fbc
                    attributes:
                      locationId: 20e62581-67a5-4166-8b1f-344e9b06b58b
                      productVariantId: 018fc380-1c43-75f9-a101-49447fbadeb7
                      locationStatus: reserved
                      movementType: 'order_reserved'
                      quantity: 10
                      unitMultiplier: 1
            example-get-postings-with-relations:
              value:
                data:
                  - type: 'posting'
                    id: 018fc386-3078-75b3-8e75-6bed4e01c144
                    attributes:
                      locationId: 20e62581-67a5-4166-8b1f-344e9b06b58b
                      productVariantId: 018fc380-1c43-75f9-a101-49447fbadeb7
                      locationStatus: incoming
                      movementType: 'replenishment'
                      quantity: -227
                      unitMultiplier: 2
                    relationships:
                      transaction:
                        data:
                          type: 'transaction'
                          id: 018fc399-3240-78b2-abfa-e8c5df1c304f
                      state:
                        data:
                          type: 'stock-state'
                          id: 018fc380-1c43-75f9-a101-49447fbadeb7
                  - type: 'posting'
                    id: 018fc386-4c76-76cf-9319-533c7dd9b66c
                    attributes:
                      locationId: 20e62581-67a5-4166-8b1f-344e9b06b58b
                      productVariantId: 018fc380-1c43-75f9-a101-49447fbadeb7
                      locationStatus: available
                      movementType: 'replenishment'
                      quantity: 200
                      unitMultiplier: 2
                      lotNumber: lot-Y
                      expiryDate: '2025-02-02'
                    relationships:
                      transaction:
                        data:
                          type: 'transaction'
                          id: 018fc399-3240-78b2-abfa-e8c5df1c304f
                      state:
                        data:
                          type: 'stock-state'
                          id: 018fc380-1c43-75f9-a101-49447fbadeb7
                  - type: 'posting'
                    id: 018fc3d3-cd9b-7c96-9b29-fd90bf0eff7b
                    attributes:
                      locationId: 20e62581-67a5-4166-8b1f-344e9b06b58b
                      productVariantId: 018fc380-1c43-75f9-a101-49447fbadeb7
                      locationStatus: available
                      movementType: 'replenishment'
                      quantity: 24
                      unitMultiplier: 2
                      lotNumber: lot-X
                      expiryDate: '2025-01-01'
                    relationships:
                      transaction:
        

# --- truncated at 32 KB (55 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/ankorstore/refs/heads/main/openapi/ankorstore-astral-openapi-original.yml