Connect any other store
AguMail works with any online store. WooCommerce has a ready-made plugin (Connect your store); every other store, Shopify included, whether a hosted platform without a plugin or a store you built yourself, sends the same data to the same API that plugin uses. Once it arrives, abandoned-cart emails, purchase-triggered automations, product blocks and revenue per campaign all work.
You need a developer, or a platform that can call a webhook URL with JSON. Connecting a store and sending its orders, carts and products are part of the Commerce plans. Contacts and events work on every plan: Send contacts and events from your app covers that half on its own.
1. Create an API key
Section titled “1. Create an API key”In AguMail, go to Settings → Store & API → API keys → Create key and choose Other store or your own code. Copy the key; it is shown once. Every request below sends it as a header:
Authorization: Bearer agm_…Content-Type: application/json2. Tell AguMail about your store
Section titled “2. Tell AguMail about your store”POST /api/v1/connect{ "platform": "custom", "storeUrl": "yourstore.com", "currency": "EUR" }Your store now shows under Settings → Store & API with the time it last sent data, and can be disconnected there. currency is the 3-letter ISO 4217 code your store prices in; products and carts you send without a currency of their own are priced in it. If your plan already has its stores connected, this returns 402 with the reason.
3. Send contacts first
Section titled “3. Send contacts first”Orders and carts are matched to contacts by email, and only to contacts AguMail already has. Send the customer before their first order or cart.
POST /api/v1/contacts{ "contacts": [ { "email": "sam@example.com", "firstName": "Sam", "consent": { "optedIn": true, "source": "checkout" } }] }Only send optedIn: true, or a consentedAt, for people who agreed to marketing email. A new contact sent without either is saved as Never subscribed: your abandoned-cart, browse-abandonment and after-purchase flows can email them, and campaigns and every other flow cannot. To email subscribers only, open those flows and click Add a filter under Who can enter on the trigger, or Add a filter for this email under Only send if on an email. The first rule it adds is Email permission is Subscribed.
4. Send your products
Section titled “4. Send your products”POST /api/v1/products{ "products": [ { "externalId": "sku-101", "sku": "TOTE-LIN-01", "title": "Linen tote bag", "price": 38, "currency": "USD", "categories": ["Bags", "Gifts"], "imageUrl": "https://yourstore.com/img/tote.jpg", "productUrl": "https://yourstore.com/p/tote" }] }Products fill the product picker in the email editor, and give cart lines their picture when a cart arrives without one.
sku and categories are what make “bought this” and “ordered from Gifts” segments possible: AguMail copies them onto every order that contains the product, so you can build an audience from what someone actually put in their basket. Both are optional, and leaving categories out of a later update keeps whatever the product already has.
5. Send orders, with the campaign they came from
Section titled “5. Send orders, with the campaign they came from”POST /api/v1/orders{ "orders": [ { "externalId": "1042", "email": "sam@example.com", "total": 68, "currency": "USD", "occurredAt": "2026-09-12T10:15:00Z", "items": [{ "externalId": "sku-101", "sku": "TOTE-LIN-01", "title": "Linen tote bag", "qty": 1, "price": 38 }], "campaignRef": "c_7f3a…" }] }A line’s externalId is the product it names, which is how an order picks up that product’s categories. sku is optional on the line — leave it out and AguMail takes it from the product you sent.
Every link in an AguMail email carries an agm_cid query parameter. Keep it when a shopper lands on your store (a cookie or the session is enough), and send it back as campaignRef on their order. That is how each campaign and flow report shows the revenue it earned. A flow is credited when the shopper was sent one of its emails in the 7 days before the order.
6. Send carts
Section titled “6. Send carts”POST /api/v1/carts{ "carts": [ { "externalId": "cart-88", "email": "sam@example.com", "total": 68, "currency": "USD", "items": [{ "title": "Linen tote bag", "qty": 1, "price": 38, "productExternalId": "sku-101", "sku": "TOTE-LIN-01", "url": "https://yourstore.com/p/tote" }], "checkoutUrl": "https://yourstore.com/cart/recover?token=…", "lastActivityAt": "2026-09-12T09:40:00Z" }] }Send the cart again whenever it changes. A cart that sits idle for an hour counts as abandoned and starts your abandoned-cart flow for that shopper. The recovery email shows the cart’s lines and a button to checkoutUrl, so make it a link that brings this cart back, not your generic checkout page. When the shopper buys, send the cart with "status": "completed", or send the order.
7. Turn on cart recovery
Section titled “7. Turn on cart recovery”In Automations, start Abandoned Cart Recovery from the gallery. Its emails already show the cart and a button back to it. Review them, then turn the flow on.
8. Send your own events
Section titled “8. Send your own events”Anything else your business records can be sent as an event, and is then something a segment can count, a flow can start from, and an email can print.
POST /api/v1/events{ "events": [ { "email": "sam@example.com", "metric": "Booked appointment", "occurredAt": "2026-09-19T10:15:00Z", "uniqueId": "appt_991", "value": 49, "properties": { "service": "Cut & finish", "staff": "Ana" } }] }metricis your own name for what happened. Spelling and capitals do not matter: “Booked appointment”, “booked_appointment” and “Booked Appointment” are one event.uniqueIdis your name for this particular occurrence — an appointment id, an invoice number. Send it and you can safely retry: the same id is never recorded twice, and nobody is enrolled in a flow twice for it.occurredAtis when it happened, not when you sent it. Leave it out and AguMail uses now.propertiesis anything you want the email to be able to say. Up to 30 keys.valueis money, if the event is worth some.
Then, in AguMail:
- Segment on it. In the segment builder pick Did something…, choose your event, and set a count and a window — “at least 1 time in the last 30 days”. Add narrow by property to ask about one of your own properties, for example
service is Cut & finish. - Trigger a flow with it. In the flow editor choose the Any recorded event trigger and pick your event. It appears in that list once the first one has arrived.
- Print it in the email.
{{event.service}}and{{event.staff}}render what that contact’s event carried. A missing property renders as nothing rather than breaking the email.
The response counts what happened: { "ok": true, "created": 1, "duplicates": 0, "unknownContacts": 0 }. unknownContacts is the important one — an event for an address AguMail does not hold is skipped rather than creating a contact, because an event is not permission to email someone. Send the person to /api/v1/contacts first.
Unlike products, orders and carts, events are not part of the store half of the API: every plan can send them.
Loading your store’s history
Section titled “Loading your store’s history”When you first connect, send your past customers and orders too, so segments and revenue start from the whole picture. Mark those batches as history with "backfill": true:
POST /api/v1/orders{ "backfill": true, "orders": [ … ] }The flag works the same on /api/v1/contacts, /api/v1/orders and /api/v1/events. History is stored like any other data, but it starts no flows: nobody gets a welcome, a thank-you or an event-triggered email for something that happened before it reached AguMail.
Two contact fields carry a past customer’s real dates. customerSince is when they became your customer. It becomes their Date added when AguMail creates the contact, so flows timed from Date added do not treat history as new. consentedAt is the date they opted in to marketing email. Send it only for people who opted in, because AguMail counts it as an opt-in.
POST /api/v1/contacts{ "backfill": true, "contacts": [ { "email": "sam@example.com", "customerSince": "2024-03-02T09:00:00Z", "consent": { "optedIn": true, "source": "checkout" }, "consentedAt": "2024-03-02T09:00:00Z" }] }AguMail applies the same rule without the flag. An order whose occurredAt, or a contact whose consentedAt, is more than 72 hours old is treated as history anyway. Leave the flag off for what happens from now on, so your flows can react to it.
Limits and errors
Section titled “Limits and errors”- 120 requests a minute per key, and up to 500 records per request.
400means a field is missing or malformed; the message names it.401means the key is missing, wrong or revoked.402means the request is part of the store half of the API (/api/v1/connect, orders, carts and products) and your plan is not a Commerce plan, or your plan has no room for another store. The message says which.429means you are over the rate limit. TheRetry-Afterheader, andretryAfterin the body, say how many seconds to wait before you send the request again.
What the API does not do
Section titled “What the API does not do”The API does not watch your store’s own pages. Carts, orders and events are what your store’s backend sends. Product views come from the website tracking snippet in Settings → Store & API → Website tracking instead: paste it on your store’s pages and browse-abandonment flows can follow up with people AguMail already knows, such as someone who arrived from one of your emails.