shopify_graphql
Run any Shopify Admin GraphQL query or mutation from Python. Octocom attaches the store's token and calls Shopify from its fixed IP.
shopify_graphql(context, query, variables=None, *, api_version, shop=None) -> dictThe only way to call the Shopify Admin API from Python. Octocom sends the request from its own servers with the store's access token, so your code never holds a Shopify token, and every request comes from Octocom's fixed IP address, which Shopify's IP allowlist requires.
SHOPIFY_API_VERSION = "2026-10"
def execute_action(context):
result = shopify_graphql(
context,
"query($q: String!) { orders(first: 5, query: $q) { nodes { id name displayFulfillmentStatus } } }",
{"q": f"email:{context['args']['email']}"},
api_version=SHOPIFY_API_VERSION,
)
if result.get("errors"):
return {"success": False, "error": "Shopify could not search orders."}
return {"success": True, "orders": result["data"]["orders"]["nodes"]}| Name | Type | Description |
|---|---|---|
context | dict | The context object passed to your code |
query | str | The GraphQL query or mutation |
variables | dict | None | GraphQL variables |
api_version | str | Required. The Admin API version, for example "2026-10" |
shop | str | None | The store's myshopify.com domain. Any store connected to a business in your organization can be named; get_integration_credentials lists them. Omit it to use the current business's first connected store. |
Returns Shopify's response body: {"data": ..., "errors": [...], "extensions": {...}}. GraphQL errors and a mutation's userErrors are returned, not raised, so check them. Throttled requests are retried for you. A mutation is never resent after a server error or lost connection, because Shopify may already have applied it; the helper raises instead.
Raises requests.HTTPError when Shopify answers with an HTTP error (for example a revoked token or a missing scope), when the store is not connected, or when the version is not accepted.
API versions
Octocom accepts only versions Shopify still supports: currently 2026-01, 2026-04, 2026-07 and 2026-10. Shopify supports each version for a year and then silently answers with a newer one, so pinning a retired version does not keep its behavior. When a version retires, Octocom moves stored automations to a newer one.
Newer versions also add rules a query validator cannot see. From 2026-04, refundCreate (and Shopify's inventory and location mutations) require an idempotency key:
REFUND = """
mutation Refund($input: RefundInput!, $idempotencyKey: String!) {
refundCreate(input: $input) @idempotent(key: $idempotencyKey) {
refund { id }
userErrors { field message }
}
}
"""
result = shopify_graphql(
context,
REFUND,
{"input": refund_input, "idempotencyKey": str(uuid.uuid4())},
api_version="2026-10",
)Use a new key for each refund you mean to send. Reusing a key returns the first attempt's result instead of refunding again.
REST
The REST Admin API is not available from Python: Shopify made it legacy in October 2024, and every REST operation has a GraphQL equivalent. For order lookups by number or email, shopify_get_order and shopify_find_orders are built on this helper.
Product-sync parsers
Product-sync parsers get the same helper without context: shopify_graphql(query, variables=None, *, api_version, shop=None). It only reaches the stores of the business being synced.
See Shopify Custom Actions for a worked playbook.