Skip to content
Cycle Counts

Cycle Counts

In this section, we will guide you through the process of managing cycle counts using the GraphQL Public API.

Cycle counts allow you to verify on-hand inventory by creating batches of items or locations to count. To manage a full cycle count flow, you will go through the following steps:

  1. Create a cycle count batch (by items or by locations)
  2. Monitor the batch status until it is ready to count
  3. List existing cycle counts to review all batches for a warehouse
  4. Create a recount for any items with discrepancies

1. Create a cycle count batch

The first step is to create a cycle count batch. There are two ways to create one, depending on whether you want to count by items (SKUs) or by locations.

Create by Items

Use the cycle_count_items_create mutation to count specific SKUs. You can provide a list of SKUs, or use item_filters to target specific SKU + location pairs:

mutation {
  cycle_count_items_create(data: {
    name: "April SKU Audit"
    warehouse_id: "V2FyZWhvdXNlOjExNzkw"
    due_date: "2026-05-15T00:00:00+00:00"
    sort_by: "LOCATION_NAME_ASC"
    max_items: 50
    skus: ["SKU-001", "SKU-002", "SKU-003"]
    exclusion_filters: {
      exclusion_parameters: ["WITHOUT_INVENTORY", "BEING_COUNTED"]
      last_n_days: 7
    }
  }) {
    request_id
    complexity
    cycle_count {
      id
      name
      count_type
      queue_status
      status
      progress
      counted
      uncounted
      due_date
      created_at
    }
  }
}

You should get something like this:

{
  "data": {
    "cycle_count_items_create": {
      "request_id": "82c4d5e6f7a8b9c0d1e2f3a4",
      "complexity": 10,
      "cycle_count": {
        "id": "Q3ljbGVDb3VudEJhdGNoOjU2Nzg=",
        "name": "April SKU Audit",
        "count_type": "PRODUCTS",
        "queue_status": "QUEUED",
        "status": "uncounted",
        "progress": 0,
        "counted": 0,
        "uncounted": 0,
        "due_date": "2026-05-15T00:00:00+00:00",
        "created_at": "2026-04-21T10:00:00+00:00"
      }
    }
  }
}

Note

  • skus and item_filters are mutually exclusive — use one or the other.
  • item_filters accepts a list of { sku, location } pairs for fine-grained targeting.
  • The batch is created asynchronously. queue_status starts as QUEUED and transitions to CREATING, then READY_TO_COUNT (or ERROR / CANCELLED).
Using item_filters

To count specific SKU + location combinations:

mutation {
  cycle_count_items_create(data: {
    name: "Targeted Count"
    warehouse_id: "V2FyZWhvdXNlOjExNzkw"
    item_filters: [
      { sku: "SKU-001", location: "A01-01-01" }
      { sku: "SKU-002", location: "B02-03-05" }
    ]
  }) {
    request_id
    complexity
    cycle_count {
      id
      name
      count_type
      queue_status
      status
    }
  }
}

Create by Locations

Use the cycle_count_locations_create mutation to count all items at specific locations. You can filter by location name prefixes and location types:

mutation {
  cycle_count_locations_create(data: {
    name: "Zone A Location Count"
    warehouse_id: "V2FyZWhvdXNlOjExNzkw"
    due_date: "2026-05-15T00:00:00+00:00"
    sort_by: "LOCATION_NAME_ASC"
    max_items: 100
    prefixes: ["A-", "B-"]
    exclusion_filters: {
      exclusion_parameters: ["WITHOUT_INVENTORY"]
      last_n_days: 14
    }
  }) {
    request_id
    complexity
    cycle_count {
      id
      name
      count_type
      queue_status
      status
      progress
      counted
      uncounted
      due_date
      created_at
      locations {
        total
        counted
      }
    }
  }
}

You should get something like this:

{
  "data": {
    "cycle_count_locations_create": {
      "request_id": "92d5e6f7a8b9c0d1e2f3a4b5",
      "complexity": 10,
      "cycle_count": {
        "id": "Q3ljbGVDb3VudEJhdGNoOjkwMTI=",
        "name": "Zone A Location Count",
        "count_type": "LOCATIONS",
        "queue_status": "QUEUED",
        "status": "uncounted",
        "progress": 0,
        "counted": 0,
        "uncounted": 0,
        "due_date": "2026-05-15T00:00:00+00:00",
        "created_at": "2026-04-21T10:15:00+00:00",
        "locations": {
          "total": 0,
          "counted": 0
        }
      }
    }
  }
}

Note

  • prefixes filters locations by name prefix (e.g., ["A-", "B-"] matches locations like A-01-01, B-02-03).
  • location_type_ids restricts the count to specific location types.
  • max_items limits the number of locations included in the batch.

Available exclusion filters

The exclusion_parameters field supports the following values:

ValueDescription
WITHOUT_INVENTORYExclude locations/items with no inventory
WITH_INVENTORYExclude locations/items that have inventory
SELLABLEExclude sellable items
NON_SELLABLEExclude non-sellable items
PICKABLEExclude pickable items
NOT_PICKABLEExclude non-pickable items
ACTIVEExclude active items
INACTIVEExclude inactive items
FLAGGED_FOR_RECOUNTExclude items flagged for recount
NOT_FLAGGED_FOR_RECOUNTExclude items not flagged for recount
BEING_COUNTEDExclude items already on an active cycle count

Additionally, last_n_days excludes items/locations counted within the last N days, and exclude_location_type_ids excludes specific location types.

Available sort options

The sort_by field supports:

  • QUANTITY_ASC / QUANTITY_DESC
  • LOCATION_NAME_ASC / LOCATION_NAME_DESC
  • LAST_COUNTED_ASC / LAST_COUNTED_DESC
  • ITEM_NAME_ASC / ITEM_NAME_DESC

2. Monitor the batch status

After creating a cycle count, the batch is processed asynchronously. Use the cycle_count query to check its current status and progress:

query {
  cycle_count(id: "Q3ljbGVDb3VudEJhdGNoOjU2Nzg=") {
    request_id
    complexity
    data {
      id
      legacy_id
      name
      warehouse_id
      account_id
      count_type
      queue_status
      status
      progress
      counted
      uncounted
      due_date
      started_at
      ended_at
      created_at
      updated_at
      locations {
        total
        counted
      }
      skus {
        total
        counted
      }
    }
  }
}

You should get something like this:

{
  "data": {
    "cycle_count": {
      "request_id": "62a1b2c3d4e5f6a7b8c9d0e1",
      "complexity": 1,
      "data": {
        "id": "Q3ljbGVDb3VudEJhdGNoOjU2Nzg=",
        "legacy_id": 5678,
        "name": "April SKU Audit",
        "warehouse_id": "V2FyZWhvdXNlOjExNzkw",
        "account_id": "QWNjb3VudDo2MzM0",
        "count_type": "PRODUCTS",
        "queue_status": "READY_TO_COUNT",
        "status": "in_progress",
        "progress": 40,
        "counted": 4,
        "uncounted": 6,
        "due_date": "2026-05-15T00:00:00+00:00",
        "started_at": "2026-04-21T11:00:00+00:00",
        "ended_at": null,
        "created_at": "2026-04-21T10:00:00+00:00",
        "updated_at": "2026-04-21T14:00:00+00:00",
        "locations": {
          "total": 8,
          "counted": 3
        },
        "skus": {
          "total": 10,
          "counted": 4
        }
      }
    }
  }
}

Note

  • queue_status tracks the creation process: QUEUEDCREATINGREADY_TO_COUNT (or ERROR / CANCELLED).
  • status tracks counting progress: uncountedin_progressclosed.
  • progress is a percentage (0–100) of items counted.

3. List existing cycle counts

Use the cycle_counts query to list all cycle count batches for a warehouse. You can filter by status, count type, SKU, date range, and customer account (for 3PL accounts):

query {
  cycle_counts(
    warehouse_id: "V2FyZWhvdXNlOjExNzkw"
    status: ["uncounted", "in_progress"]
    count_type: [PRODUCTS]
    date_from: "2026-04-01T00:00:00+00:00"
    date_to: "2026-04-30T23:59:59+00:00"
  ) {
    request_id
    complexity
    data(first: 10) {
      edges {
        node {
          id
          name
          count_type
          queue_status
          status
          progress
          counted
          uncounted
          due_date
          created_at
          locations {
            total
            counted
          }
          skus {
            total
            counted
          }
        }
        cursor
      }
    }
  }
}

You should get something like this:

{
  "data": {
    "cycle_counts": {
      "request_id": "72b3c4d5e6f7a8b9c0d1e2f3",
      "complexity": 11,
      "data": {
        "edges": [
          {
            "node": {
              "id": "Q3ljbGVDb3VudEJhdGNoOjU2Nzg=",
              "name": "April SKU Audit",
              "count_type": "PRODUCTS",
              "queue_status": "READY_TO_COUNT",
              "status": "in_progress",
              "progress": 40,
              "counted": 4,
              "uncounted": 6,
              "due_date": "2026-05-15T00:00:00+00:00",
              "created_at": "2026-04-21T10:00:00+00:00",
              "locations": {
                "total": 8,
                "counted": 3
              },
              "skus": {
                "total": 10,
                "counted": 4
              }
            },
            "cursor": "YXJyYXljb25uZWN0aW9uOjA="
          }
        ]
      }
    }
  }
}

Note

Available status values: uncounted, in_progress, closed.

Available count_type values: PRODUCTS, LOCATIONS, RECOUNT.

Other filters: customer_account_id (for 3PL accounts), sku, date_from / date_to.

4. Create a recount

After a cycle count is completed, some items may have discrepancies between the expected and actual quantities. Use the cycle_count_recount_create mutation to create a new batch that targets those items. If no SKUs are specified, all items with discrepancies are included:

mutation {
  cycle_count_recount_create(data: {
    name: "April Recount"
    warehouse_id: "V2FyZWhvdXNlOjExNzkw"
    due_date: "2026-05-01T00:00:00+00:00"
    sort_by: "QUANTITY_DESC"
    max_items: 25
    skus: ["SKU-001", "SKU-003"]
  }) {
    request_id
    complexity
    cycle_count {
      id
      name
      count_type
      queue_status
      status
      progress
      counted
      uncounted
      due_date
      created_at
    }
  }
}

You should get something like this:

{
  "data": {
    "cycle_count_recount_create": {
      "request_id": "a2e6f7a8b9c0d1e2f3a4b5c6",
      "complexity": 10,
      "cycle_count": {
        "id": "Q3ljbGVDb3VudEJhdGNoOjM0NTY=",
        "name": "April Recount",
        "count_type": "RECOUNT",
        "queue_status": "QUEUED",
        "status": "uncounted",
        "progress": 0,
        "counted": 0,
        "uncounted": 0,
        "due_date": "2026-05-01T00:00:00+00:00",
        "created_at": "2026-04-21T10:30:00+00:00"
      }
    }
  }
}

Note

  • If skus is omitted or empty, all items with discrepancies from previous counts are included.
  • exclude_location_type_ids can be used to skip specific location types during the recount.
  • vendor_ids and tags provide additional filtering options.
  • After creating the recount, use the cycle_count query to monitor its progress.