# Shopify

Abandoned cart reminders, order confirmations, shipping updates with the tracking link, and OTP codes — sent from your templates, at your plan prices. Links become tracked short links on your short domain.

## Connect {#connect}

1. Portal › Integrations › Shopify: enter `your-store.myshopify.com` and click **Connect**.
2. Shopify asks you to approve read access to checkouts, orders, customers and fulfillments. You come back to the portal connected.
3. Choose the sender ID, enable the events you want and edit the texts. Start in **test mode** to see the SMS in your message log without sending.

Security: the OAuth `state` is single use, valid 10 minutes and bound to your login; Shopify's `hmac` is checked on every callback; the access token is stored encrypted. Every webhook is checked against `X-Shopify-Hmac-Sha256` (HMAC-SHA256 of the raw body with the app secret) and the shop domain; repeated deliveries are ignored. Uninstalling the app in Shopify disconnects it here.

## Events and templates {#events}

| Event | Shopify webhook | When the SMS goes out |
| --- | --- | --- |
| Abandoned cart | `checkouts/create`, `checkouts/update` | N minutes (default 60, 15–2880) after the checkout started, if no order was placed for it. Link: Shopify's recovery URL. |
| Order created | `orders/create` | Right away (also closes the checkout: no reminder) |
| Order shipped | `fulfillments/create` | Right away, with the carrier's tracking link |

Variables: `{first_name}` `{store}` `{order_number}` `{total}` `{currency}` `{cart_url}` `{tracking_url}` `{tracking_number}` `{carrier}`. One SMS per event and order, never two. Every event (sent, skipped, failed) is in the connection's log.

## OTP codes (login / checkout confirmation) {#otp}

Enable **OTP code** and add an **app proxy** (subpath `apps/sms` → `https://app.ogave.co/integrations/shopify/proxy`). Your theme then calls, from the storefront:

```
fetch('/apps/sms/otp/start', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({phone: '+573001234567'})})
// → {"verification_id": "ver_…", "status": "pending", "expires_at": "…"}
fetch('/apps/sms/otp/check', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({verification_id: 'ver_…', code: '123456'})})
// → {"result": "approved" | "invalid" | "expired" | "max_attempts"}
```

Shopify signs proxy requests (`signature`); we refuse unsigned ones. Codes are sent by Verify (one Verify app per store: same code rules, fraud limits, prices and logs).

## Platform setup (admins) {#admin}

Create a public app in the Shopify Partner dashboard. App URL `https://app.ogave.co/integrations/shopify/install`, redirect URL `https://app.ogave.co/integrations/shopify/callback`. Paste the client ID and secret in Admin › Settings › Integrations.
