Connect Shopify (Preview)
Preview · Available to selected organizations. Connect a Shopify store to Samva from the Settings page in your organization's dashboard.
Connecting a Shopify store links it to your Samva organization. Connect and disconnect from Settings → Integrations in the dashboard, let an agent use it to answer order questions, and start journeys from store activity. This page is available in Preview.
Connect from the dashboard
Open Settings in your organization's dashboard, choose Integrations, and locate the Shopify card.
- Enter your store's
.myshopify.comdomain in the Shop domain field, for exampleyour-store.myshopify.com. - Choose Connect. Samva redirects your browser to Shopify to authorize the connection.
- Approve the requested access in Shopify. If the app is already installed, Shopify can return you directly to Samva. The Integrations page confirms the connection.
The Integrations page shows the shop domain, who connected it, the connection date, and a Disconnect button.
Connect after installing in Shopify
Open Samva from Shopify after installing the app. Sign in to Samva if prompted. Samva opens Settings → Integrations in your last-used organization, or your first organization if you have not selected one, with the shop domain filled in.
Check that you are in the organization you want to connect. An organization administrator must choose Connect and finish authorization before the store is connected to Samva.
Connect from the API
The connect endpoint is gated behind the agents permission resource and requires an organization
administrator. The OAuth callback that finishes the connection requires the same administrator's
active dashboard session; an API key alone cannot complete it. Use the dashboard to connect a
store.
If your workflow starts the flow programmatically, the endpoint is
POST /v1/integrations/shopify/connect. Supply the returnTo field as a root-relative dashboard
path, for example /dashboard/acme/settings/integrations, not an absolute URL.
Let an agent answer order questions
After the store shows as connected, open the agent's Connect step and switch the store on. The agent can then look up order status, tracking, delivery date, and refunded amount, and tell the customer how long they have to return an order. See Answer order questions from Shopify for what the agent can and cannot do.
- Sender only. The agent looks up orders for the address that emailed in. It cannot search other customers, and an order number that belongs to someone else returns nothing. The sender authentication requirements also apply to replies using earlier order details.
- Read only. The agent never cancels, refunds, or creates returns. It hands those requests to a person.
- Return window and order history. See the lookup limits for how the return deadline is calculated and which orders are available.
Start journeys from store activity
A connected store records contact events as customers buy, receive, and return orders. A
journey starts from one of these events the same way it starts from a
custom event, with an event trigger and the event's name. The store's customer
becomes a contact, identified by email.
| Event | Recorded when |
|---|---|
shopify.order_created | A customer places an order |
shopify.order_fulfilled | The store fulfills an order |
shopify.order_delivered | A shipment first shows as delivered |
shopify.refund_created | The store refunds an order |
shopify.checkout_started | A checkout first has a usable email, on creation or update |
Order events carry an order object and the shop. Checkout events carry a checkout object
and the shop.
| Property | Meaning |
|---|---|
order.name | The order number the customer sees, for example #1042 |
order.total | The order total as a decimal string |
order.currency | The order's currency code |
order.statusUrl | An optional order status link; may be null |
order.items[] | Each line: title, quantity, price, and imageUrl |
checkout.checkoutUrl | A link that returns the customer to their checkout |
shop | The store's .myshopify.com domain |
A checkout carries total, currency, and items[] like an order. Events leave out addresses and
phone numbers. An order with many lines carries the first lines only. order.statusUrl is null
when no authorized link is available; templates must handle a missing link. A journey email reads these values as event.*;
declare event in the template's input schema, as described in
Send an email. Item prices are decimal strings; quantities are
numbers. Image and status links are null when unavailable.
Each delivery from Shopify records at most one event, so a retried delivery does not start a second
run. A checkout records shopify.checkout_started once per store and checkout, at the first create
or update with a usable email. Opening a guest checkout without an email records nothing; later
updates do not start another run after the event is recorded.
Contacts and consent
Each event finds or creates a contact by email. Order events use the order's email, falling back to
the customer's current email when the order has none. The Shopify customer GID is assigned as
externalId only when the recipient matches the customer's current email. An update for an older
order keeps its original recipient without moving that GID back to a previous contact. Samva also
updates contacts when customer details change in Shopify. Previous contact history stays separate.
Samva preserves externalId values set manually or by another store. If an existing key prevents a
Shopify GID assignment, the event still records against the contact matched by email.
Marketing consent follows the customer's email subscription in Shopify:
| Shopify subscription | In Samva |
|---|---|
| Subscribed | The contact gets the tag shopify-subscribed |
| Unsubscribed | The tag is removed and the contact is opted out of email |
| Not subscribed | No change |
Consent updates are ordered separately for each Shopify customer and email address. Subscribing
never removes a Samva email opt-out. A customer who never subscribed can still enter post-purchase
journeys. Email opt-outs and other suppressions still apply. Branch on the shopify-subscribed tag
before sending marketing.
Recipes
Each recipe creates a journey with the SDK. Templates named here are templates you
publish first. Publish the journey with journeys.publish
as shown in Create and publish a journey.
Post-purchase check-in. Send a thank-you, wait three days, then ask how the order is going.
import { createClient } from "samva";
const samva = createClient({ apiKey: process.env.SAMVA_API_KEY! });
await samva.journeys.create({
name: "Post-purchase check-in",
definition: {
trigger: { type: "event", eventName: "shopify.order_created" },
rootNodeId: "thanks",
nodes: {
thanks: {
type: "send_email",
config: { template: "order-thanks" },
next: [{ nodeId: "pause" }],
},
pause: { type: "wait", config: { durationSeconds: 259200 }, next: [{ nodeId: "check-in" }] },
"check-in": {
type: "send_email",
config: { template: "order-check-in" },
next: [{ nodeId: "done" }],
},
done: { type: "exit", config: {}, next: [] },
},
},
});Return-window reminder. Start when the shipment is delivered, wait for most of the return window, then remind the customer how to return. Set the wait to match your store's actual return policy; this example waits five days.
await samva.journeys.create({
name: "Return-window reminder",
definition: {
trigger: { type: "event", eventName: "shopify.order_delivered" },
rootNodeId: "pause",
nodes: {
pause: { type: "wait", config: { durationSeconds: 432000 }, next: [{ nodeId: "remind" }] },
remind: {
type: "send_email",
config: { template: "return-window-reminder" },
next: [{ nodeId: "done" }],
},
done: { type: "exit", config: {}, next: [] },
},
},
});Checkout reminder. Start when a customer begins a checkout and wait for an hour. If the contact
orders in that time, exit. Otherwise remind contacts tagged shopify-subscribed and exit for
everyone else.
await samva.journeys.create({
name: "Checkout reminder",
definition: {
trigger: { type: "event", eventName: "shopify.checkout_started" },
rootNodeId: "wait-for-order",
nodes: {
"wait-for-order": {
type: "wait_for_event",
config: { eventName: "shopify.order_created", timeoutSeconds: 3600 },
next: [
{ nodeId: "done", outcome: "matched" },
{ nodeId: "consent", outcome: "timed_out" },
],
},
consent: {
type: "branch",
config: {},
next: [
{
nodeId: "remind",
condition: {
match: "all",
predicates: [{ type: "tag", tag: "shopify-subscribed", present: true }],
},
},
{ nodeId: "done" },
],
},
remind: {
type: "send_email",
config: { template: "checkout-reminder" },
next: [{ nodeId: "done" }],
},
done: { type: "exit", config: {}, next: [] },
},
},
});The reminder template links to event.checkout.checkoutUrl.
Limits
- A contact has one live run per journey. A customer who orders again while their post-purchase
run is active does not start a second run, and a customer is not re-enrolled unless the journey
sets
reentrytotrue. wait_for_eventmatches the event by name for the contact. Anyshopify.order_createdafter the wait begins counts, including an order unrelated to the checkout.- Branches test tags, contact properties, custom fields, and whether an event occurred. They cannot test an event's properties, such as an order's total or its items.
- Events are recorded only while journeys are available for your organization and the store is connected.
Store ownership
A Shopify store connects to one Samva organization at a time. If you supply an
existing integrationId in the connect request, Samva reconnects that integration rather than
creating a new one.
Reconnection
Samva refreshes the Shopify access token automatically. If Shopify revokes the access or the refresh credential expires, the integration status changes to Needs reconnecting. Open Settings → Integrations, choose Reconnect, and complete the authorization flow. The shop domain, return-window setting, and connection history are preserved.
If Samva cannot confirm that Shopify finished connecting the store, connection and disconnect attempts are refused briefly. Wait a minute, then connect again.
Disconnect
Disconnect removes the integration and its saved access from Samva. For a working connection, Samva also asks Shopify to uninstall the app. If the connection needs reconnecting or Shopify is unavailable, uninstall Samva in Shopify Admin to remove the app there.
If Samva cannot confirm that Shopify finished uninstalling, disconnect fails and reconnection stays blocked. Contact Samva support to verify the uninstall before reconnecting.
Disconnect retains contacts, commerce events, and journey history. Shopify privacy requests still erase the store's attributed history after the connection is removed.
To disconnect through the API, send a DELETE to the integration's own URL. The request carries
no body:
curl -X DELETE https://api.samva.dev/v1/integrations/intg_… \
-H "x-api-key: $SAMVA_API_KEY"Uninstall
Uninstalling the Samva app from your Shopify Admin marks the integration as Needs reconnecting
and retains the integration record. Shopify later sends a shop/redact request to remove the
saved data for that uninstalled connection. If you reconnect first, a delayed request for the
earlier uninstall preserves your working connection and its attributed contact, commerce, and
journey history.
Privacy requests
Samva acknowledges customer data requests (customers/data_request) from Shopify within the
required window.
When Shopify sends customers/redact, Samva deletes that customer's shopify.* contact events
in every Samva organization that retains history from the addressed store, clears names and
externalId values still assigned
by that Shopify customer, and removes their shopify-subscribed tags. Shopify can identify the
customer by ID or email; the ID takes precedence when both are present. An email-only request
includes matching guest activity and Shopify customer history across email changes. Explicitly
listed orders are erased even when the request has no usable customer ID or email.
The contacts, fields you have replaced, and non-Shopify history remain. Email opt-outs and other suppressions remain to protect recipients from unwanted email. Matching event data stored in journey history is cleared, including copies whose original event has expired; the journey records remain. Previously rendered or sent emails and conversation history are not deleted. Delayed activity from before the erasure request cannot restore the erased data. Activity without a usable Shopify timestamp is ignored after erasure. New activity after the request can record customer data again, with existing email opt-outs still applied. Erased orders and checkouts cannot be restored. Later updates to an erased checkout do not start another checkout reminder.
Samva retains the store-to-organization association and hashed erasure markers and email-to-customer associations so later erasure requests can still find Shopify history after disconnect.
For a confirmed uninstall or a disconnected store, shop/redact removes any remaining Shopify
connection and erases all of that store's commerce events,
Shopify-assigned contact fields and subscription tags, and copied journey entry data. Contacts,
fields you have replaced, history from other stores, imported contact history, topic subscriptions,
and email opt-outs remain. Customer and store erasure requests work even when the store is
disconnected or commerce events are unavailable for your organization. Hashed erasure records remain
to prevent delayed activity from restoring erased data.
Samva reads the store's name and .myshopify.com domain once during connection to verify the shop
identity. Order lookups and journey events read current Shopify data. Commerce events store the projected
order or checkout fields on the contact's event history; customer updates store the contact's name
and Shopify customer ID. The returned order details appear in the
conversation's tool-action history and may be included in the agent's reply.