Shopify orders
MarkdownSayproof reading orders from Shopify itself; app details, setup, status mapping, the delivery rule and showing reviews on the product page.
On a store that runs on Shopify, no code needs to be written to get orders to Sayproof. Sayproof connects to the Shopify Admin API with the details of a Shopify app you install on your store and reads new or changed orders itself at regular intervals (every 15 minutes by default). The orders read are recorded in the same way as orders sent by your store system; the right to write a review and the invitations follow the same rules.
The Shopify screen names on this page are those of the English admin; if your Shopify admin is in another language, the same places appear under their translated names.
When to use it
Section titled “When to use it”- If your store runs on Shopify, set up the connection on this page.
- If your system has no ready connection, your store system sends the orders: Sending orders and deliveries.
In the panel the two ways are shown one under the other on the Integration › Order transfer tab: Read from your platform and Sent by your store.
What you need
Section titled “What you need”| Item | Description |
|---|---|
| Shopify store address | Your store’s myshopify.com address, for example yourbrand.myshopify.com. It is shown in the Shopify admin under Settings › Domains. You do not need to write https://; if you do, only the domain is used. Your own domain (yourbrand.com) and the admin.shopify.com address are not accepted. |
| Client ID and Client secret | The details of the app you create for this job in the Shopify Dev Dashboard and install on your store. The app only needs the read_orders scope. |
| Sayproof channel | The channel the orders read are written to. The order’s market is this channel’s market. |
- By default Shopify gives apps the orders of the last 60 days. Even if How many days to read back the first time is set above 60, older orders do not arrive; for those the app also needs the
read_all_ordersscope, which depends on Shopify’s approval. - The customer’s email address is protected customer data in Shopify. Apps created in the Dev Dashboard can access it; for custom apps created the old way in the store admin, access depends on the store’s Shopify plan. If the Has email column shows No in the try, the app cannot read the email and no invitation can be sent for those orders. The order’s phone number is protected customer data too; if the app cannot read it, the field arrives empty and the read does not stop.
A Sayproof channel can have one connection per platform.
Creating the app in Shopify
Section titled “Creating the app in Shopify”New custom apps can no longer be created in the Shopify admin; the app is created in the Shopify Dev Dashboard:
- In the Dev Dashboard, under Apps, press Create app, choose Start from Dev Dashboard and give the app a name (for example “Sayproof”).
- On the app’s Versions page, write
read_ordersin the Scopes field and publish the version with Release. - Open the app and install it on your store with the Install app button on the Installs card.
- Copy the Client ID and Client secret values on the App settings page.
The app and the store must belong to the same organisation in Shopify; Sayproof asks your store for a token with these details. If a scope is added later, a new version is released and the change is approved on the store.
If you already have a custom app created earlier in the store admin (Apps › Develop apps), you can also use its Admin API access token with the read_orders scope: leave the Client ID field empty and write the token in the Client secret field.
Setting up in the panel
Section titled “Setting up in the panel”- On the Integration › Order transfer tab, press Set up a connection in the Read from your platform section.
- In the Where to read from step, choose Shopify as the platform and the Sayproof channel.
- In the Connection details step, fill in Shopify store address, Client ID and Client secret. How many days to read back the first time takes a value between 1 and 365; the default is 30 days.
- In the Try it step, press Try the connection. Sayproof connects to Shopify and reads the first page (at most 25 orders) of the orders within the chosen number of days. The result shows the number of orders read, the orders that could not be read and at most five sample orders: Order no., Order date, Payment, Products, Shipping status, Has email. The customer’s email address is not shown. Nothing is saved in this step.
- Save and start reading only becomes available after a successful try. If any detail changes after the try, the connection has to be tried again.
After saving, the connection appears on the Platform connections card. The card shows Read frequency, Last read, In the last read (orders read and how many were new), Could not be read and Last error. Buttons:
| Button | Purpose |
|---|---|
| Read now | Starts a read without waiting for the next one. It is unavailable while the connection is paused or the channel is off. |
| Try the connection | Repeats the try with the saved details; saves nothing. |
| Pause / Resume | Stops reading or starts it again. |
| Edit the connection | Changes the Shopify store address and the Read frequency (between 5 and 1440 minutes). Reading continues where it left off; orders already transferred are not read again. If the address points to another store, the Client ID and Client secret are entered again in the same form; the saved details are not sent to the new address (400 invalid / address_needs_credentials). The Sayproof channel does not change in this form. |
| Change the sign-in details | Saves the new Client secret; if the Client ID is left empty, the current value is kept. |
| Remove the connection | Stops reading. Orders already read and invitations already sent are not deleted. |
Reading
Section titled “Reading”- A read runs every 15 minutes by default; the frequency can be changed to between 5 and 1440 minutes with Edit the connection. The first read takes the orders whose change time falls within the chosen number of days.
- Later reads take the orders changed since 10 minutes before the previous read started. Reading the same order again is safe: the order is updated and no duplicate is created.
- Only one read runs at a time for a connection.
- A read takes at most 50 pages (at most 25 orders per page). If Shopify finds a page’s query cost too high, the page is asked for again with fewer orders. If the limit is reached before the orders run out, the card shows “The last read hit the page limit” and the next read continues from the change time of the last order read (with a 10-minute margin).
- If Shopify reports that the request limit has been reached, the read stops at that page and the next read continues where it left off. If this happens on the first page, the read counts as failed.
- If a read fails, its position does not move; the next read tries the same range again after the read interval and the reason appears on the Last error line.
If Client ID is filled in, Sayproof gets a token from your store with the app details at the start of each read; if Client ID is empty, the old custom app token in the Client secret field is used directly. The token is valid for 24 hours and is not stored by Sayproof.
POST https://yourbrand.myshopify.com/admin/oauth/access_tokenContent-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_id=<client id>&client_secret=<client secret>Orders are read from version 2026-10 of the GraphQL Admin API, sorted by change time:
POST https://yourbrand.myshopify.com/admin/api/2026-10/graphql.jsonContent-Type: application/jsonX-Shopify-Access-Token: <token>
{"query": "query SayproofOrders($first: Int!, $after: String, $query: String!) { orders(first: $first, after: $after, query: $query, sortKey: UPDATED_AT) { … } }", "variables": {"first": 25, "after": null, "query": "updated_at:>='2026-09-02T12:00:00Z'"}}- Further pages are reached with the
pageInfo.endCursorvalue of the answer. - If the token is not accepted (
401) and Client ID is filled in, Sayproof gets a new token once; if an old custom app token is not accepted, the read stops withapi_credentials_refused. - Each request times out after 30 seconds and an answer may be at most 20 MB.
Fields read
Section titled “Fields read”| Information in Sayproof | Field read in Shopify |
|---|---|
| Order number | name (for example #1001) |
| Payment status | displayFinancialStatus |
| Order date | createdAt |
| Change time | updatedAt |
| Cancellation | cancelledAt |
| Customer email | email |
| Customer phone | phone |
| Language | customerLocale (first part only; tr-TR → tr) |
| Product lines | lineItems; the order’s first 50 lines |
| Line identifier | The number at the end of the line’s id |
| Product code | The line’s sku; the variant’s legacyResourceId when empty |
| Group code | The product’s legacyResourceId (product.id in Liquid) |
| Product name | The line’s name |
| Quantity | currentQuantity; quantity when it is zero |
| Line status | The displayStatus of the shipments the line is in (fulfillments, the order’s first 5 shipments); see Delivery rule |
- The customer email does the same job as the
customer_emailfield in the order data sent by a store system: the invitation is sent to this address and the order is verified with it. - The customer phone does the same job as the
customer_phonefield in the order data: the number is for invitations on WhatsApp. Until invitations by WhatsApp arrive with v2, the phone number is not stored. - The product code must match the product key in your product source and the code given to the container on the product page.
- The customer record is not read, so the app does not need the
read_customersscope. The order’s address, price and payment details are not stored in Sayproof.
Status mapping
Section titled “Status mapping”The payment status comes from the order’s displayFinancialStatus:
| Value in Shopify | Meaning | Payment |
|---|---|---|
PENDING |
Payment pending | Payment pending |
AUTHORIZED |
Payment authorised, not captured yet | Payment pending |
PARTIALLY_PAID |
Partially paid | Payment pending |
PAID |
Paid | Paid |
PARTIALLY_REFUNDED |
Partially refunded | Partially refunded |
REFUNDED |
Refunded | Refunded |
VOIDED |
Authorisation voided | Voided |
EXPIRED |
Authorisation expired | Voided |
Each line’s shipping status comes from the displayStatus of the shipment the line is in, or from the Sayproof codes below:
| Code | When | Shipping status |
|---|---|---|
UNFULFILLED |
The line is not in a shipment yet | Placed |
SUBMITTED, LABEL_PURCHASED, LABEL_PRINTED, LABEL_VOIDED |
The shipment is being prepared | Preparing |
FULFILLED, MARKED_AS_FULFILLED, CONFIRMED, FAILURE |
The shipment was created; a shipment with an empty displayStatus also counts as FULFILLED |
Shipped |
CARRIER_PICKED_UP, IN_TRANSIT, OUT_FOR_DELIVERY, DELAYED, ATTEMPTED_DELIVERY, NOT_DELIVERED, READY_FOR_PICKUP |
The shipment is on its way or ready for pickup | In transit |
DELIVERED, PICKED_UP |
The shipment was delivered or the customer picked it up | Delivered |
CANCELLED |
The order was cancelled (cancelledAt is set) |
Cancelled |
REMOVED |
The whole line was refunded or removed from the order before it was shipped | Cancelled |
REFUNDED |
The whole line was refunded after it was in a shipment | Returned |
- Cancelled, errored or failed shipments (
statusofCANCELLED,ERRORorFAILURE) and shipments whosedisplayStatusisCANCELEDare not taken into account. - The table also appears in the How statuses are matched section of the connection card in the panel.
- If a value that is not in the table arrives, the order or line is not read and is counted on the Could not be read line.
Delivery rule
Section titled “Delivery rule”- A line counts as Delivered when the shipment it is in has the status
DELIVEREDorPICKED_UP. The delivery date is the shipment’sdeliveredAt, or itsupdatedAtwhen that is empty. - If a line is split over several shipments, the shipment with the furthest status is used.
- A shipment’s status reaches Shopify from carrier tracking or from apps that add delivery events to the shipment. Shipments that never get a delivery in Shopify stay Shipped or In transit, and no invitation is sent for those lines.
- For invitations and the right to write a review, the line must be Delivered and the order Paid or Partially refunded. The invitation is sent once the waiting time on the Invitation sending screen has passed.
Orders that could not be read
Section titled “Orders that could not be read”| In the panel | Reason |
|---|---|
| number or date missing | The order has no name, no createdAt or no list of product lines |
| status not recognised | If the order’s payment status is not in the table the order is skipped; if a line’s shipment status is not, only that line is skipped |
| product code missing on a line | The line has no identifier, or both sku and the variant are empty; the line is skipped |
| no readable product lines | None of the order’s lines could be read |
| more than 50 product lines; the first 50 were read | The order’s first 50 lines were saved and the remaining lines were not read |
| could not be saved in Sayproof | The order was read but could not be saved in Sayproof (for example, there is no rule for the channel’s market) |
Orders that could not be read or saved do not stop the read; the other orders are saved. If none of the orders read can be saved, the read counts as failed and its position does not move; the reason appears on the Last error line.
Failures
Section titled “Failures”| In the panel | Meaning |
|---|---|
| the address is not a Shopify store address; write it as yourbrand.myshopify.com | The address is not of the form <store>.myshopify.com; no request is sent |
| the keys needed for the connection are missing | The Client secret is empty |
| the platform did not accept the keys | Shopify refused the token request (400, 401, 403) or did not accept the token (401) |
| the app or key has no permission to read orders | The app has no read_orders scope or the scope was not approved on the store |
| requests were sent too often | Shopify reported that the request limit had been reached (on the first page) |
| the domain could not be reached | The store address could not be resolved |
| couldn’t connect to the server, a secure connection could not be made | The connection or the TLS handshake failed |
| the source did not answer in time | The request got no answer within 30 seconds |
| the address redirects elsewhere; enter the direct address | Shopify returned a redirect; redirects are not followed |
| the other system returned an error, status code | Shopify answered with something other than 200 (for example http_status: 402 if the store is frozen, http_status: 423 if it is unavailable) |
| the platform’s answer could not be read, the platform’s answer is too large | The answer is not JSON, does not contain the expected order list or is larger than 20 MB |
| the stored sign-in details couldn’t be read; enter them again | The saved details could not be decrypted; enter them again with Change the sign-in details |
| the read stopped with an unexpected error | An unexpected error occurred; the read is tried again after the read interval |
Showing reviews on the product page
Section titled “Showing reviews on the product page”Reviews are shown on the product page with the script. In Shopify, the script and the container are added to the theme’s product template with a Custom Liquid block:
- In the Shopify admin, under Online Store › Themes, press Customize on your theme.
- Open the product template (Products › Default product) from the page picker at the top.
- In the section where the reviews should appear, add a Custom Liquid block with Add block, paste the code below and press Save.
<script type="module" src="https://cdn.sayproof.example/sayproof.js" data-review-site-key="YOUR-SITE-KEY" data-review-base="https://api.sayproof.example" data-review-locale="en"></script><div data-review-mount data-review-product="{{ product.selected_or_first_available_variant.sku | default: product.selected_or_first_available_variant.id }}" data-review-product-name="{{ product.title | escape }}"></div>- The
srcanddata-review-site-keyvalues are in the Values for the setup list on the Show reviews on the product page card on the Integration › Showing reviews tab in the panel when the Script (in the browser) route is chosen. data-review-productis the SKU of the variant selected when the page opens (or the first available one); when the SKU is empty, the variant number is used. This matches the product code Sayproof reads from the order.- The theme does not update the container when a variant is chosen. To show the reviews of all of the product’s variants together, add
data-review-scope="group"and setdata-review-productto{{ product.id }}; the group code is the product number in Shopify.
Domain verification
Section titled “Domain verification”Reviews only appear on pages of verified domains. Because files cannot be placed at the site root in Shopify, the domain is verified with a DNS record:
- Add the domain in the panel; for example
www.yourbrand.com. See Domain verification. - In the “How to verify
<domain>” section, choose DNS record as the Verification method. In your domain’s DNS settings, add aTXTrecord with the Name (_sayproof-verification.www.yourbrand.com) and Value the panel shows. If the domain was bought through Shopify, its DNS records are edited in the Shopify admin under Settings › Domains. - Once the record is added, press Verify in the panel. The record can take from a few minutes to a few hours to appear.
Each domain where reviews are shown is verified separately. If customers see your own domain rather than the myshopify.com address, verify that domain.
Security
Section titled “Security”- The Client secret (or the earlier custom app’s Admin API access token) is stored encrypted and never shown again in the panel or in API answers. The token Shopify gives during a read is not stored.
- Only
https://<store>.myshopify.comis contacted; private network addresses and redirects are refused. - The app only has read access; Sayproof changes nothing in Shopify. To cut the connection completely, uninstall the app from your store.
- Connections are only seen and managed by a user signed in to the panel with the “Can change settings” permission; these actions cannot be taken with an API key.
- Setting up, changing, trying, reading manually and removing are recorded on the Activity history screen.