Selling through a WooCommerce shop
You run a WooCommerce shop and want buyers — programs buying on a person's behalf — to buy from it without anybody writing code. The WooCommerce page of your dashboard connects the shop, imports its products, and from then on the shop takes the paid orders. This page is what each of those steps does to your shop, your products on Agentify and your money.
The connector runs on the test channel, where the money is not real, and on the live channel, where buyers pay in real USDC on Base. Each channel has its own dashboard and its own account, so you connect the shop on each one. On the live channel nothing is published until an Agentify operator has approved your business, which you ask for at admin@agentify.ad: Import says so and reads nothing from your shop, and you import again once you are approved (How to start). A purchase on the test channel makes a paid order in the shop connected there, as a live one does. Its Agentify lines say it came from the test channel and was paid in test USDC, which is not real money, so do not ship goods for it.
What can be imported ​
The connector imports a product only when it is a published simple product that WooCommerce marks purchasable and in stock, whose stock is not counted and which is not limited to one in an order (Sold individually). A shop priced in US dollars sells at its own prices; a shop priced in another currency sells at a rate you set, as A shop priced in another currency describes. The shop's own settings have to allow it too, as Settings of your whole shop describes.
Such a product is imported as one of two kinds:
| The product in your shop | What the buyer gets | What your shop gets |
|---|---|---|
| A virtual download with exactly one protected file, unlimited downloads and no expiry | the download, once it is paid for | a paid order |
| A physical product, neither virtual nor downloadable | a parcel: it pays the price plus your shop's cheapest shipping rate to the buyer's place, and any tax your shop charges there | a paid order carrying the buyer's shipping address |
Every other product stays in your shop untouched, and the import names it with the reason. A product also needs a name and a description in plain text, because the description is what a buyer reads before it decides to buy.
At every purchase the connector asks your shop for the product's price, and for a parcel the shipping rate, and your shop has four seconds to answer. A shop slower than that loses that sale before any payment, and only the connector's own log, which your dashboard does not show, records why.
The buyer gets a download through Agentify: once your shop has created the order, the order the buyer reads from us carries your shop's private download address for the file, the file's name and the order's number in your shop, and the file itself comes from your shop at that address.
Each order is created in your shop with your own dashboard email as the customer's, so the shop's customer emails — the confirmation, the download link — come to you and never to the buyer, and the shop's reports name you as the customer of every sale.
An order your shop totals at what the buyer paid, or within a cent of it, is
taken on: the order carries what the buyer paid among its Agentify lines
(agentify_paid), and your Orders screen shows the shop's total beside it
where the two differ, so your shop's books can differ by a cent from the
USDC you received for that sale. An order further from it is not taken on. In
a shop priced in another currency the same holds in that currency, with one of
its smallest written amounts, a rupiah where prices have no decimals, in place
of the cent.
Settings of your whole shop ​
A few of the things the connector needs are settings of the whole shop rather than of one product, so changing one to sell through Agentify changes it for every customer of the shop, not only for Agentify's buyers. Most of them are WooCommerce's or WordPress's defaults, and a shop that never changed them has nothing to change; the import names any setting that stands in a product's way, and where to find it. What a shop that calculates tax needs is in the next section.
A shop priced in US dollars has to write its prices with two decimals (WooCommerce → Settings → General → Number of decimals), which is WooCommerce's default; a shop priced in another currency with no decimals or with two. That setting is how many decimals every price in the shop is shown with, to every customer.
Permalinks have to be anything other than Plain (Settings → Permalinks, in
WordPress), because a site with Plain permalinks does not serve the addresses
the connector reaches WooCommerce at, its approval screen among them. Plain is
WordPress's own default, so a shop may well still use it. Switching to another
structure changes the address of every page, post and product on the site,
from the form ?p=123 to the structure you choose. WordPress sends a visitor
who follows the old address of a page or a post on to its new one, but neither
WordPress nor WooCommerce does so for a product's old address, written
?product= and the product's name, so check where such a link now leads
before you count on links already shared, printed or found through a search
engine.
A download needs four settings under WooCommerce → Settings → Products → Downloadable products to stand at WooCommerce's defaults: the file download method set to Force downloads, redirect mode not allowed as a last resort, Downloads require login off, and access granted to downloadable products after payment. Together they keep the file behind its download link and hand it to a buyer, who has no account in your shop, as soon as the order is paid. Each of them applies to every downloadable product in the shop. Force downloads sends every customer's files through your site itself and keeps their address hidden, and WooCommerce warns that some servers deliver large files unreliably that way. With redirect mode not allowed, a file the chosen method cannot deliver is no longer handed to the customer by its open address, so that download fails instead. With login not required, a registered customer's download link works without signing in, as a guest customer's always does, for whoever holds the link. Granting access after payment gives every customer their files once an order is paid and Processing, rather than only once you mark it Completed.
A parcel needs the shop's shipping switched on (WooCommerce → Settings → General → Shipping location(s), anything but disabling shipping) and not forced to the billing address (WooCommerce → Settings → Shipping → Shipping destination), both WooCommerce's defaults. Switching shipping on brings it into every customer's cart and checkout: a physical product then asks where it goes, is charged the rates of your shipping zones, and can be ordered only to a place one of your zones has a shipping method for. Moving the shipping destination off "Force shipping to the customer billing address" lets every customer enter a shipping address other than their billing one at checkout; the connector needs it because an Agentify order carries the buyer's address as its shipping address.
Shops that calculate tax ​
Where WooCommerce calculates tax in your shop, nothing sells unless it rounds tax at the subtotal (WooCommerce → Settings → Tax → "Round tax at subtotal level, instead of rounding per line"), and the import leaves every product in your shop otherwise. Rounding on each line, WooCommerce's default, a tax that comes to exactly half a cent can be rounded up in your cart and down in the order made for the sale, so the order would record a cent other than what the buyer paid; rounding at the subtotal, the cart and the order agreed in every case measured. Switching it on changes how WooCommerce rounds the tax of every order your shop takes, not only Agentify's: on the one-item orders measured the tax moved by a cent at most, as when a 20.00 parcel with 1.50 of shipping at 19% came to 21.78 rounding per line and 21.79 at the subtotal, and orders of several lines were not measured.
What sells then depends on how your prices are entered (WooCommerce → Settings → Tax → Prices entered with tax):
| Your shop | A download | A parcel |
|---|---|---|
| Tax calculation off | sells at its price, and the order carries no tax | sells at its price plus your cheapest shipping rate to the buyer's place |
| Prices entered with tax inside them | sells at its price, and the order records the tax inside it at the rate of your shop's own address | sells at what your shop's cart charges for the buyer's place, but only to a place your shop taxes at the same rates as its own address |
| Prices entered before tax | not imported | sells at what your shop's cart charges for the buyer's place: the goods, your cheapest shipping rate and the tax on both there |
A buyer of a download gives no address, so its order is created without one, and WooCommerce then taxes it at your shop's own address. Where your prices hold their tax, the buyer pays the price Agentify shows wherever they are, and the order shows the tax of your own address inside that price. Where your prices are entered before tax, the tax would be added for your own city on every buyer's price, whoever and wherever the buyer is, so such a download is left in your shop.
A parcel's price is asked of your shop's own cart for the buyer's place at every purchase, so the buyer pays what your cart charges there at your cheapest shipping rate, tax included, and the order your shop then records charges the same. Where your prices hold their tax, WooCommerce takes the tax of your own address out of the price and adds the tax of the buyer's place. Code added to a shop can keep one price for every buyer instead, and the connector cannot tell from outside whether yours does; the cart then shows that one price while the order created for the parcel still moves it to the buyer's rate. So a parcel from such a shop sells only to a place your shop taxes at the same rates as its own address, and a buyer elsewhere is told before paying that the parcel is not available there. A parcel also needs tax to be calculated on the customer's shipping address (Calculate tax based on), which is WooCommerce's default. A shop that set it to the billing address or to the shop's own address and sets it back taxes every shipped order by the place it goes to, so a customer whose order goes somewhere taxed otherwise than that address pays the tax of where it goes. Its price question also asks your cart about your own address, within the same four seconds.
The import also leaves in your shop every product of a shop whose catalogue shows prices otherwise than they are entered (Display prices in the shop), because the import reads the catalogue's price while a buyer pays the price as entered. Changing that setting changes whether every visitor to your catalogue sees its prices with tax or without it.
Tax calculated by an outside service, such as WooCommerce Tax, TaxJar or Avalara, is not supported. The connector cannot see such a service from outside, and nothing has measured what it does to an order made through the connector. If the order your shop records then charges something other than what the buyer paid, the connector does not take that order on: the sale ends unfulfilled on your Orders screen, your shop holds a paid order you should not fulfil, and you settle it by your own policy.
Each of these settings applies to your whole shop, so changing one to sell through Agentify changes what every customer of the shop is charged. Whether a sale owes tax, and whether the treatment above is the right one for your shop, are yours to settle; this page does not answer them.
Connecting your shop ​
You type the public https address at the root of your shop, and your browser goes there next so that WooCommerce can ask you to approve access. Approve read and write: with read alone, every purchase is refused before payment, because Agentify cannot create the order in your shop. Agentify never asks for your shop password.
Before your browser leaves for the shop, Agentify reads one product from your shop's public catalogue to learn the currency it is priced in and the decimals it writes. A shop priced in another currency than US dollars is refused there, before you approve anything and with nothing changed in how you sell, when its prices are written with any number of decimals other than none or two, or when Coinbase gives no rate for its currency. When Coinbase does not answer, Connect stops and asks you to press it again in a moment. When the catalogue gives no clear answer, because the shop has no products yet or does not serve its public catalogue, Connect goes ahead and the import names each product it cannot sell.
Every request the connector makes to your shop names itself with the User-Agent
Agentify/1 (+https://agentify.ad), so if a firewall or security plugin in
front of your shop blocks visitors it does not recognise, let that one through:
a shop that refuses it cannot be connected, imported or sold from. A paid
download is fetched from your shop's private download address by the buyer,
not by Agentify, so that address has to stay open to any visitor.
Your shop sends the keys to Agentify in a request of its own, separate from your browser coming back. The dashboard waits fifteen minutes for them. If none arrive, it cannot tell whether you declined, closed the approval screen, or the shop's request failed, and you press Connect again; where WooCommerce showed an error, it has already removed the key from that attempt.
Your account is connected to one shop at a time. Connecting the same shop again renews its keys. To connect a different shop, disconnect the one that is connected first, which waits for the orders still waiting on it to end. A shop is known by its address, so a shop that has moved to a new address counts as a different shop.
To revoke the keys in the shop yourself, open WooCommerce → Settings → Advanced → REST API.
The connector works on up to four stream messages at once for your shop, so one slow order creation need not delay the next purchase or price question. If all four are busy, later questions wait and may expire. A repeat of an order already being created shares that attempt; the connector's durable record still prevents a second shop creation after a restart.
A shop priced in another currency ​
A shop priced in another currency than US dollars, such as rupiah, sells at an exchange rate you set on the WooCommerce page of your dashboard: how many units of your currency one US dollar buys, written in digits, such as 18000 for eighteen thousand rupiah, with a dot only before a fraction and nothing between thousands. The currency is your shop's own setting, read from the shop; you do not choose it, and a shop priced in US dollars is asked for no rate. Nothing from such a shop is published until you set one, and saving a rate imports your products again, so they are listed at prices in dollars at it.
A buyer pays in US dollars, as USDC: your shop's price, or for a parcel your cart's total, divided by your rate and rounded up to the next cent, so, for example, a product priced Rp 240.000 at 18000 rupiah to the dollar sells for 13.34 USD. The buyer is told the dollar price and nothing about your rate. Agentify takes no currency margin, and its 0.1% commission is of the USDC paid. What that USDC is worth in your currency when you sell it depends on your exchange and its spread, which your rate should allow for.
Beside the field the page shows Coinbase's open rate, with the moment Agentify read it, because Coinbase's answer carries no time of its own. It is there to catch a mistyped rate and decides no price. A rate more than a tenth away from it is saved only once you type it a second time, and the page shows what a product of yours would then cost in dollars: the first of the first ten in your shop's public catalogue with a price, or, where none of them has one, says so. A rate written the wrong way round, or with a digit missing, is the mistake this catches. When Coinbase does not answer, the rate is saved all the same, with a note that it was not compared with anything. Every rate saved is sent to your account's email address with the rate before it and when the session that saved it signed in, and a rate whose message could not be sent is not saved, because a rate nobody was told of could sell your goods for cents unseen. Every rate you have saved is kept.
Your rate keeps selling until you change it, however old it is, and also after you disconnect the shop and connect it again: the page shows when it was entered, when the session that saved it signed in, and how far it now stands from Coinbase's, and keeping it current is yours. Neither the page nor the message names an address as who entered the rate, because every session of your account carries your address, a session somebody copied from your browser included; for the same reason a sign-in moment you recognise does not prove it was you. Where the moment that session signed in is not recorded, the page says so rather than name one. A price a buyer was given holds at the rate it was given at, even if you change the rate before the order reaches your shop, because the buyer has paid by then. If your shop's currency changes, every purchase is refused before payment until you set a rate for the new one; a rate set for the old currency is never applied to it. Should the shop change back to a currency you set a rate for before, the last rate you set for it applies again.
Your shop's order is made in your currency at your own price, and its Agentify
lines carry what the buyer paid in USDC (agentify_paid), the amount it was
priced at in your currency (agentify_shop_amount) and the rate with the
moment you set it (agentify_rate). Your Orders screen shows the same for the
sale, for example "240000 IDR in your shop, paid as 13.34 USDC at your rate of
18000 IDR per US dollar".
Your shop or your code, one at a time ​
You sell through the shop or through your own code with the Agentify SDK, never both. You move to the shop when it sends Agentify its keys, which it does the moment you approve access: from then the products your code published are off sale and your code receives no orders until you disconnect the shop. The WooCommerce page says how many products that takes off sale before you press Connect. Until the keys arrive nothing changes, so if you decline or close the approval screen, your code goes on selling as before. Keys that grant less than Read/Write switch nothing either, because every purchase through them would be refused; the page asks you to connect again and approve Read/Write.
Connect and Sell through this shop are refused while an order from your code is still open, and each such order has to end first. A purchase its buyer has not paid yet ends within a minute, paid or lapsed, so the page asks you to try again then. An order your code took on ends when your code delivers or refuses it, or when its time runs out; the page names those orders and links to them on Orders. If you paused all sales on Products to keep new orders from arriving meanwhile, selling stays paused after the switch until you resume it there.
An order from your code can also open while you are approving. The shop is then connected when its keys arrive, but you keep selling through your code, and the WooCommerce page offers Sell through this shop to press once that order has ended.
If you sell through the shop while none is connected, nothing sells. The WooCommerce page offers the way back to your own code; its products come back with selling stopped until you resume it on Products.
Importing ​
An import reads up to 2,000 products and publishes the ones the connector supports. A shop with more than 2,000 products is refused whole rather than cut short. Running the import again updates the products it published before and does not double them, and a product you paused stays paused through it.
The page answers once every product has been read and published, so a large shop takes a while: the import asks your shop for a hundred products at a time, a few requests at once, and how long that takes depends on how quickly your shop answers. If you leave the page, the import carries on and the products it publishes appear on Products, but its list of what was published and what was not shows only on the page that started it. One import of a shop runs at a time; pressing Import again while one runs reads nothing and says so. A shop that reports more than 2,000 products is refused on the first page it answers.
Nothing is read until the name your products are sold under is set in Settings, and the wallet your share is paid out to on a channel where payments settle: without them every product would be refused, so Import stays unavailable and says which of them to set. A shop priced in another currency imports nothing until its rate is set, which the page asks for first.
The result lists every product it read under one of these headings, in this order:
| Heading | What happened | What you do |
|---|---|---|
| To fix | Agentify's publishing rules refused it, in the sentences shown, or the connector left it for something the shop can change, such as a product not published or a download limit | change what they name and import again; a length is counted with the formatting removed, so your shop's editor shows a larger number |
| No verdict | Agentify did not answer about it, so whether it was published is not known | import again; it does not double products |
| Not attempted | the import stopped at the first product with no verdict | import again |
| Not supported | the connector does not sell its kind, such as a variable or grouped product, a product with stock tracking, or a download that also ships | nothing in Agentify; the connector does not take the product as it is |
| Published | the product is on Products, folded under the other headings | nothing; whether it sells is on Products |
When a product changes in the shop ​
A product deleted from the shop, sold out, or no longer supported stays on Products, but the price check refuses its purchase before payment. Pause the products you no longer want buyers to see. A change that lands after a buyer was quoted and before the order is placed, such as a new price, or for a parcel a different shipping rate, leaves that paid sale unfulfilled on your Orders screen, because the connector checks the product and the rate again before it creates the order and refuses what no longer matches what was paid.
Parcels ​
These rules describe what Agentify records about a parcel. Whether it arrives, and what you do for the buyer if it does not, are yours and your shop's.
- Ship within seven days of payment and mark the order Completed in WooCommerce, in the shop it was sold from. The seven days are Agentify's number, because WooCommerce has no field for it.
- An order not marked Completed within its seven days shows on your Orders screen as unfulfilled. Marking it Completed later, within thirty days of the order being placed, still records the shipment, unless you have closed fulfillment of it.
- Completed tells the buyer the parcel has shipped, and it cannot be taken back. Where the order has a fulfilled WooCommerce fulfilment, the buyer gets its carrier and tracking; otherwise the buyer is told your shipping method's name as the carrier, with no tracking number.
- An order you cancel or refund in WooCommerce has not shipped, and shows as unfulfilled when its seven days run out.
- If Orders shows an order as unfulfilled before its seven days are up while your shop holds a paid order for it, do not ship that order: Agentify could not confirm it with your shop. Close fulfillment of it on Orders with an explanation for the buyer, and settle the shop order by your own policy.
- A parcel is published only once your shop's site is set in Settings, because the site is where a buyer asks about a parcel that did not arrive.
To stop Agentify accepting delivery for an order, use Orders → Order details → Close fulfillment (what closing does). It changes nothing in your shop — no setting, no cancellation, no refund — so stop the shop's own work on that order yourself. Your explanation, if you give one, is shown to the buyer as your words.
Recovering a download ​
If a paid download was not delivered and the connector has a saved sale it can check, your Orders screen offers Recover WooCommerce delivery on that order. The recovery page shows the Agentify order ID, the product, the amount and the shop the sale came from.
When the connector refused a download before it sent anything to your shop, your shop holds no order for it. This happens, for example, when the shop did not answer the product check at the time of the sale, or when the product had changed since its price was given. Connect the same shop again on the WooCommerce page, put the product back the way it was sold if it changed, and press Create shop order on the recovery page. Agentify then makes the order in your shop once, at the price the buyer paid, and delivers the download when the shop places it. If the shop refuses before anything is sent, the page says why, and you can press again once that is fixed. If the shop's answer to the create does not arrive, nobody knows whether the order exists, so the page never offers the create again: find the order in your shop and link it, as described next.
When the shop's answer to creating the order never arrived, find the order in
that same shop whose Transaction ID is this Agentify order ID, and enter its
Shop order ID: the internal number in the order's address in WooCommerce,
after id= or post=, which can differ from the order number customers see.
Link and deliver checks that exact order and product against the saved
sale, then delivers the download; it does not search for another order or
create one. If your shop
holds no order with that Transaction ID, nothing can be delivered from this
page: close fulfillment on Orders with an explanation for the buyer.
When the shop order and its download are already saved, Retry delivery sends that same download to Agentify, even after you disconnect the shop or switch to your own code. If an answer was lost, the page offers a reload in place of the button: it shows the saved order and says whether Agentify confirms the delivery. A check that could not be made leaves the result unknown, which is not proof that nothing was recorded, and a saved order cannot be replaced by a different one.
Recovery makes or links the download's one shop order and delivers the download, and does nothing else. To stop delivery instead, close fulfillment on Orders; a closed order has no recovery action, and neither has a parcel. A parcel refused before its shop order was made cannot be made later, because Agentify does not keep its delivery address.
Disconnecting ​
Disconnecting removes the keys your shop gave Agentify and switches you back to your own code. The shop's products stay on Products, off sale, and the products your code published come back with selling stopped until you resume it there.
The orders still waiting on the shop have to end first, because once it is disconnected nothing reads the shop: a parcel ends when it is marked Completed in WooCommerce, an unpaid purchase when its buyer pays or lets it lapse, any of them when its time runs out, and a paid one when you close fulfillment of it on Orders. A parcel already unfulfilled is no longer followed after you disconnect, so marking it Completed then records no shipment in Agentify.
Disconnecting does not revoke the keys inside your shop; that is done in WooCommerce → Settings → Advanced → REST API.
What is not settled yet ​
- How long a parcel has to ship. The connector gives every parcel seven days, a number of Agentify's own, because WooCommerce has no field for it.
- How a buyer reaches your support to arrange a remedy outside Agentify.
- Whether a merchant in Indonesia may accept USDC through Agentify for goods priced in rupiah, given the country's Currency Law; Agentify has not settled it, and whether a sale is lawful where your shop is remains yours to judge.
- Downloads from a shop whose prices are entered before tax, which would need the buyer's address at the moment the price is asked; parcels from a shop whose prices hold their tax to a place taxed otherwise than the shop's own address; and tax calculated by an outside service. See Shops that calculate tax.