E-commerce

AI Agents for Shopify

A phone and web agent that answers "where is my order" from live shop data instead of a FAQ page - and hands the conversation on when it cannot.

Assisted setupShopify · bitpull AI agents

Where this stands today

Shopify support volume is dominated by a handful of questions: where is my order, can I still change it, is this size in stock, what does delivery cost to my country. All four have a definite answer sitting in the Shopify Admin API, and none of them need a human to look it up.

bitpull has no Shopify app in the App Store. What it has is function calling: you declare a tool on the agent - a name, a description the model reads to decide when to call it, and a JSON Schema for the arguments - and the agent calls it mid-conversation. The declaration is self-serve in the dashboard. The endpoint that declaration executes against is not part of the public agent object, so that side is wired up with the bitpull team.

Everything after the conversation is separate and simpler: the outbound webhook posts the finished conversation, and your own function creates the follow-up in whatever system owns it.

What the agent can do

Order status by order number or email

The agent asks for the order number, calls a lookup tool, and reads back the fulfilment state and tracking link. This is the single highest-volume question in most shops.

Stock and variant availability

A product_availability tool taking an SKU or a product name returns inventory for the variant. The agent can then offer the closest available alternative instead of a dead end.

Delivery and returns policy

Static policy text does not need a tool at all - crawl the shipping and returns pages into the agent knowledge and it answers from there, in the caller's language.

Callback and escalation

When the answer needs a human - a damaged parcel, a refund dispute - the agent takes the callback details and the webhook drops them into your helpdesk with the transcript attached.

How it is wired

  1. Caller asks"Where is order 1043?"
  2. Agent selects toolorder_status(order_number)
  3. Your endpointShopify Admin API
  4. Result to the modelJSON, within the timeout
  5. Spoken answerin the caller's language
Live lookup during the conversation. The post-call webhook is a separate path.

Code

Tool declaration - bitpull agent → Tools tab
{
  "name": "order_status",
  "description": "Look up the fulfilment status and tracking link of a Shopify order. Use when the caller asks where their order is, whether it shipped, or when it will arrive.",
  "parameters": {
    "type": "object",
    "properties": {
      "order_number": { "type": "string" },
      "email": { "type": "string" }
    },
    "required": ["order_number"],
    "additionalProperties": false
  },
  "responseTimeoutMs": 4000,
  "enabled": true
}
Name pattern is [A-Za-z0-9_-]{1,64}. Parameters must be a JSON Schema object; responseTimeoutMs accepts 1000–60000.
Your lookup endpoint - Shopify Admin API
// POST /agent/order-status  →  called by your bitpull tool wiring
import { json } from './http.js'

const SHOP = process.env.SHOPIFY_SHOP          // my-shop.myshopify.com
const TOKEN = process.env.SHOPIFY_ADMIN_TOKEN  // Admin API access token
const API = '2024-10'

export async function orderStatus({ order_number, email }) {
  const q = new URLSearchParams({ name: `#${order_number}`, status: 'any', limit: '1' })
  const res = await fetch(
    `https://${SHOP}/admin/api/${API}/orders.json?${q}`,
    { headers: { 'X-Shopify-Access-Token': TOKEN } }
  )
  if (!res.ok) return { found: false, reason: 'lookup_failed' }

  const [order] = (await res.json()).orders ?? []
  if (!order) return { found: false, reason: 'not_found' }

  // Only hand back what the agent is allowed to say out loud. Never return the
  // full order object - it carries addresses, prices and customer records that
  // have no business in a spoken answer to an unverified caller.
  if (email && order.email?.toLowerCase() !== email.toLowerCase()) {
    return { found: false, reason: 'mismatch' }
  }

  const shipment = order.fulfillments?.[0]
  return {
    found: true,
    status: order.fulfillment_status ?? 'unfulfilled',
    placed_at: order.created_at,
    tracking_url: shipment?.tracking_url ?? null,
    carrier: shipment?.tracking_company ?? null
  }
}
Keep it boring and fast. The model is waiting inside a live conversation; a slow tool becomes an audible pause.
After the call - webhook → Shopify customer note
// Your endpoint, configured as the agent's outbound webhook URL.
export default async function handler(req, res) {
  const body = req.body ?? {}

  // Read defensively: the envelope is not a published contract, so pull the
  // fields out by several plausible names rather than assuming one shape.
  const summary   = body.summary ?? body.session?.summary ?? {}
  const outcome   = summary.outcome ?? 'UNKNOWN'
  const transcript = body.messages ?? body.transcript ?? []

  if (outcome === 'RESOLVED') return res.status(200).end()   // nothing to do

  await fetch(`https://${SHOP}/admin/api/2024-10/customers/${customerId}.json`, {
    method: 'PUT',
    headers: {
      'X-Shopify-Access-Token': process.env.SHOPIFY_ADMIN_TOKEN,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      customer: {
        id: customerId,
        note: [summary.title, ...(summary.keyPoints ?? [])].filter(Boolean).join('\n')
      }
    })
  })

  res.status(200).end()   // always answer fast; do the slow work out of band
}
The payload shape is not part of the published API. Point the webhook at a throwaway inbox first, read the real delivery, then write the mapping against what you actually received.

Limits worth knowing before you start

  • There is no bitpull listing in the Shopify App Store, and no OAuth install flow. Access is your own Admin API token held by your own endpoint.
  • A tool declaration in the dashboard does not by itself reach Shopify. The mapping from declaration to endpoint is set up with the bitpull team.
  • Identity is weak on a phone call. An order number spoken by an unverified caller should never unlock an address or a payment detail - return the shipping state and nothing more.
  • Shopify Admin API rate limits are per shop, not per caller. A lookup on every call is fine; a lookup loop inside one call is not.
  • Storefront prices, discounts and taxes shift per market. Quoting them out loud from a cached crawl invites a complaint - read them live or do not say them.

Questions

Does bitpull have a Shopify app?

No. There is no App Store listing and no OAuth install. Shopify is reached through a declared agent tool that calls your own endpoint, which in turn calls the Shopify Admin API with your token.

Can the agent take an order over the phone?

Nothing in the platform creates a Shopify order. Treat a phone order as a callback request: the agent collects what it needs, the webhook delivers it, and a human completes the checkout.

How fast does the lookup have to be?

Fast enough not to be heard. The tool timeout is configurable between 1000 and 60000 ms, but anything past roughly a second is a silence in a spoken conversation. Cache what you can.

Ready to run this?

Agents are created and operated on bitpull.ai - this site documents how to connect one. If the outbound webhook is not visible in your dashboard yet, that is the account capability flag, and support can enable it.