AbandonedCheckouts GraphQL query filters not working as expected

I am performing a Bulk Operation for Orders, Customers and AbandonedCheckouts that have been updated within a date range.
The bulker operation query works fine and I can download the JSONL files.
The date range query filter works fine for the Customers and Orders, but not for the AbandonedCheckouts. I get records returned for Customers and Orders, but 0 records returned for AbandonedCheckouts when I know records exist during that timeframe as I have tested getting all the records and can see them.

My GraphQL Query (in Dotnet C#) for AbandonedCheckouts inside the bulk operation query is:

abandonedCheckouts(query:\"updated_at:>=" + fromDT + " AND updated_at:<" + toDT + "\") { edges { node { id billingAddress { city country countryCodeV2 province provinceCode zip } completedAt createdAt customer { id firstName email } updatedAt totalPriceSet { shopMoney { amount currencyCode } } } } }

which returns 0 records regardless of the DateTime variable values for fromDT and toDT.
If I change the filter to first or last it returns ALL of the AbandonedCheckouts for the shop, not just first x or last x.

As I mentioned, this exact same filter and query structure works for Customers and Orders so I’m wonderiing if there is something different about AbandonedCheckouts that I am missing?

Hey @TroyH ,

If you test your query outside of the bulk operations does it work? I would recommend testing that and adding in the syntax debugging headers to get a clear view of how it’s being parsed.

Thanks @KyleG-Shopify . I’m not sure how to add that header using ShopifySharp.GraphQL but I’m getting the following responses for the following queries outside the bulk operation:

  1. abandonedCheckouts(first: 10) { edges { node { id billingAddress { city country countryCodeV2 province provinceCode zip } completedAt createdAt customer { id firstName email } updatedAt totalPriceSet { shopMoney { amount currencyCode } } } } }
    Response: syntax error, unexpected IDENTIFIER (“abandonedCheckouts”) at [1, 1]

  2. query AbandonedCheckouts { abandonedCheckouts(first: 10) { edges { node { id billingAddress { city country countryCodeV2 province provinceCode zip } completedAt createdAt customer { id firstName email } updatedAt totalPriceSet { shopMoney { amount currencyCode } } } } } }
    Response: It gives me the first 10 as expected

NOTE: If I try to do this query (2) in the bulk operation it fails with

Graph user errors were returned:
System.Collections.Generic.List1[System.String]: Invalid bulk query: Field 'query' doesn't exist on type 'QueryRoot' System.Collections.Generic.List1[System.String]: Invalid bulk query: Field ‘AbandonedCheckouts’ doesn’t exist on type ‘QueryRoot’

but query (1) works but it returns ALL historical AbandonedCheckouts not just the first 10. Seems like either the filter should work or it should allow the additional “query AbandonedCheckouts {” in the bulk operation.
Noting also that for Orders and Customers the filter works fine in the format of (1) above.

  1. query AbandonedCheckouts { abandonedCheckouts(query:"updated_at:>=" + fromDT + " AND updated_at:<" + toDT + "") { edges { node { id billingAddress { city country countryCodeV2 province provinceCode zip } completedAt createdAt customer { id firstName email } updatedAt totalPriceSet { shopMoney { amount currencyCode } } } } } }
    Response: Graph errors were returned: you must provide one of first or last

  2. query AbandonedCheckouts { abandonedCheckouts(first: 10, query:"updated_at:>=" + fromDT + " AND updated_at:<" + toDT + "") { edges { node { id billingAddress { city country countryCodeV2 province provinceCode zip } completedAt createdAt customer { id firstName email } updatedAt totalPriceSet { shopMoney { amount currencyCode } } } } } }
    Response: ValueKind = Object : “{“data”:{“abandonedCheckouts”:{“edges”:[]}},“extensions”:{“cost”:{“requestedQueryCost”:14,“actualQueryCost”:2,“throttleStatus”:{“maximumAvailable”:2000.0,“currentlyAvailable”:1998,“restoreRate”:100.0}},“search”:[{“path”:[“abandonedCheckouts”],“query”:“updated_at:>=01/05/2025 00:00:00 AND updated_at:<31/05/2025 00:00:00”,“parsed”:{“and”:[{“field”:“updated_at”,“range_gte”:“2025-05-01T00:00:00+00:00”,“range_lt”:“2025-05-31T00:00:00+00:00”},{“field”:“default”,“match_all”:“00”},{“field”:“00”,“match_all”:“00”}]},“warnings”:[{“field”:“00”,“message”:“Invalid search field for this query.”}]}]}}”

NOTE: AbandonedCheckouts docs shows updated_at as a valid query field.
I can’t see any difference in the documentation between AbandonedCheckouts and Customers and I’m using the same query syntaxand filter fields but getting different results.

I’m also finding that using updated_at filter on Customers doesn’t seem to return the correct records in both the bulk query and the normal query.

  1. customers(query:"updated_at:>=" + fromDT + " AND updated_at:<" + toDT + "") { edges { node { id amountSpent { amount currencyCode } createdAt defaultAddress { city country countryCodeV2 province provinceCode zip } email firstName lastOrder { id createdAt } numberOfOrders updatedAt verifiedEmail } } }

in the bulk operation returns 3 records.

  1. query CustomerList { customers(last: 200) { edges { node { id amountSpent { amount currencyCode } createdAt defaultAddress { city country countryCodeV2 province provinceCode zip } email firstName lastOrder { id createdAt } numberOfOrders updatedAt verifiedEmail } } } }

not in the bulk operation returns the same 3 records.

However, I ran a bulk operation whcih downloaded ALL Customers for the shop and looking at the records I can see 413 records in the JSONL file that have an updatedAt property in May 2025 which is the range in the query with fromDT=01/05/2025 and toDT=30/05/2025.
Most of these 413 customers were CreatedAt in that time too which is why I know the 3 is wrong because that would mean only 3 new/updated customer in the whole month which is just wrong.
I can’t use CreatedAt because I need to make sure we have the updated data for each record which is why we are using UpdatedAt.

I figured out it is to do with the DateTime string format when converting from DateTime implicitly. Excplictly setting the format works as expected e.g.
string fromDT = new DateTime(2025, 5, 1).ToString(“yyyy-MM-ddT00:00:00Z”);
string fromDT = new DateTime(2025, 5, 1).ToString(“yyyy-MM-dd”);

Such a duh moment for me… Should have been more obvious to me considering I’m passing strings to the GrahQL service that the exact format needs to be specified rather than expecting C# to use the correct format when implicitly converting to a string.

Hopefully this helps someone else getting stuck on the same thing.

I can see now in this error message that it is parsing the date properly but then using the additional 00 after the : chars as query fields:
ValueKind = Object : “{“data”:{“abandonedCheckouts”:{“edges”:[]}},“extensions”:{“cost”:{“requestedQueryCost”:14,“actualQueryCost”:2,“throttleStatus”:{“maximumAvailable”:2000.0,“currentlyAvailable”:1998,“restoreRate”:100.0}},“search”:[{“path”:[“abandonedCheckouts”],“query”:“updated_at:>=01/05/2025 00:00:00 AND updated_at:<31/05/2025 00:00:00”,“parsed”:{“and”:[{“field”:“updated_at”,“range_gte”:“2025-05-01T00:00:00+00:00”,“range_lt”:“2025-05-31T00:00:00+00:00”},{“field”:“default”,“match_all”:“00”},{“field”:“00”,“match_all”:“00”}]},“warnings”:[{“field”:“00”,“message”:“Invalid search field for this query.”}]}]}}”

So it is the T missing from the implicit conversion, instead having a whitespace between Date and Time components which indicates to the GraphQL that the next characters are new fields in the query.

1 Like

Hey @TroyH, thanks for sharing your solution. I’m sure that will absolutely help others who run in to a similar issue.

Hi, I am new to this forum but I am having a head ache with dates, for created_at I am issuing my requests through a https POST request and the request seems to be sent correctly each time and my start date is working, but it ignores the end date totally and just keeps going?

{“query”: "query {orders(first: 250, query: "created_at:>=2025-06-01T00:00:00Z created_at:<=2025-06-01T23:59:99Z") { edges { cursor node { legacyResourceId id name confirmationNumber clientIp createdAt updatedAt sourceName currencyCode email phone customerJourneySummary { customerOrderIndex daysToConversion firstVisit { landingPage referrerUrl referralCode } lastVisit { landingPage referrerUrl referralCode } } customerAcceptsMarketing displayFinancialStatus paymentGatewayNames cancelledAt cancelReason note retailLocation { id name } customAttributes { key value } discountCodes customerAcceptsMarketing currentTotalPriceSet { shopMoney { amount currencyCode } } currentTotalTaxSet { shopMoney { amount currencyCode } } currentShippingPriceSet { shopMoney { amount currencyCode } } totalDiscountsSet { shopMoney { amount currencyCode } } refunds(first: 100) { id createdAt note totalRefundedSet { shopMoney { amount currencyCode } } refundLineItems(first: 100){ edges { node { lineItem { title sku vendor id product { id } variantTitle variant { id price } quantity originalUnitPriceSet { shopMoney { amount currencyCode } } } } } } } displayAddress { firstName lastName company address1 address2 city province provinceCode country zip countryCodeV2 id phone name } billingAddress { firstName lastName company address1 address2 city province provinceCode country zip countryCodeV2 id phone name } billingAddressMatchesShippingAddress shippingAddress { firstName lastName company address1 address2 city province provinceCode country zip countryCodeV2 id phone name } lineItems(first: 100) { edges { node { title sku vendor id product { id } variantTitle quantity originalUnitPriceSet { shopMoney { amount currencyCode } } refundableQuantity variant { id price } } } } fulfillments { status trackingInfo { number company url } } tags note customerAcceptsMarketing customer { id firstName lastName email dataSaleOptOut } } } pageInfo { hasNextPage startCursor endCursor } } } "}

It’s really annoying as I just dont seem to be able to move forward?
Thanks
Lucy

Hi Lucy,

At first glance it seems like you are missing the AND operator in between the two date conditions so

created_at:>=2025-06-01T00:00:00Z created_at:<=2025-06-01T23:59:99Z

should be

created_at:>=2025-06-01T00:00:00Z AND created_at:<=2025-06-01T23:59:99Z

Hope that helps.

Hi Troy I tried changing it to

{“query”: "query {orders(first: 250, query: "created_at:>=‘2025-06-01T00:00:00Z’ AND created_at:<=‘2025-06-02T00:00:00Z’")

But it just keeps returning next cursors in the page info showing more pages…

So I am really confused?
thanks
Lucy

Is it necessary to have the ’ around the dates? I didn’t in my example so maybe that is causing an issue?

Are you using ShopifySharp on Dotnet? If not I’m not sure if I can help you more as I would need to play around with it.

Try the syntax debugging headers as suggested by KyleG above.

I would also suggest starting another topic since my issue was different to yours.

Hi Troy,
No not using dotnet - being sent as requests from Delphi as a REST request.
I’ve tried the diags option and the results now come back clean, so I will find a coded fix to sort for now I feel.

Hey @Lucy_hutchinson,

I’ve been testing here and your syntax looks correct and should return all orders in that range.

You mentioned:

Is this returning orders with created_at dates outside of your specified range?

Sorry for delay, been away, the start date is correct but it never finishes and just keeps returning a next cursor.

Thanks, so the next pages are returning orders past the end date? ie, the created_at:<=2025-06-01T23:59:99Z is being ignored?

Can you share an x-request-id from the API response headers where this is happening?

Sorry for the delay and thanks for replying but I was away…

This is from when it has gone way past the end date

x-shopify-api-version=2025-04
x-shopify-api-deprecated-reason=Customer.email
strict-transport-security=max-age=7889238
x-request-id=d5e3aa3f-f682-486c-b4f4-693d0938ec1b-1752680684

I also turned on the diags as requested as this is returned on my first JSON Block back

“query”: “created_at:>=2025-06-01 AND created_at:<=2025-06-02”,
“parsed”: {
“field”: “created_at”,
“range_gte”: “2025-06-01T00:00:00+01:00”,
“range_lte”: “2025-06-02T23:59:59+01:00”
}

Thanks again
Lucy

Hi Lucy,

Thanks for sharing those details, it was really helpful. I did some further tests and if you keep your query field in your request along with the after:cursor then it will stop when there’s no more in range.

{
  orders(
    first: 250
    after: "EndCursorValues"
    query: "created_at:<'2025-06-02T00:00:00Z' AND created_at:>'2025-06-01T00:00:00Z'"
  )

What’s happening when you don’t include the query, it’s looking for all of the orders after the End cursor, so it will keep going until there are no more orders. The query fields aren’t encoded in the the cursor so you’ll need to keep those in your paginated query.

Amazing!
That actually makes sense now you explain it :slight_smile: And it works perfectly!
Can I suggest that maybe the online documentation on pagination is updated to reflect this?

I have one other question, when I was using the previous version and not shopifyql one of the fields available was order_number which was a different number to the field in orders called orders.name , it doesn’t appear I can access this field anymore?

And also was available as a pure number without any prefix?

It’s not essential but was just checking I am not missing anything?

E.g

“name”: “#658354”,
“number”: 657354,
“order_number”: 658354,

Only name appears to be available now on shopifyql?
thanks again
Lucy

Thanks for confirming that Lucy. I’ll pass that feedback on to our documents team.

For the order number, that was just recently added to the 2025-07 graphql version. https://shopify.dev/docs/api/admin-graphql/latest/objects/order#field-Order.fields.number

Hey Kyle!
As you were super helpful - maybe you can help on this as well?

Thanks
Lucy