App guides
The EasyPost app shows your customers live EasyPost carrier rates at checkout, and buys shipping labels from your EasyPost account, when you choose Buy EasyPost label on an order or automatically when an order is paid or submitted. After a label is bought, the app fulfills the order in Swell with the carrier and tracking number, and keeps the tracking status on the order until the parcel is delivered.
Rates and labels come from the carrier accounts in your EasyPost account, your own or the ones EasyPost provides, and labels are charged to your EasyPost account.
| When | What the app does |
| A customer enters a shipping address at checkout | Asks EasyPost for rates for one parcel and shows each carrier service as a shipping option. |
| You choose Buy EasyPost label on an order | Buys a label from your EasyPost account for the service the customer chose, or the cheapest, and creates a Swell shipment with the carrier and tracking number. |
| An order is paid or submitted, if you choose automatic labels | Buys the label the same way, without anyone choosing Buy EasyPost label. |
| You choose Void EasyPost label on an order | Asks EasyPost to refund the label and cancels the Swell shipment the app created. |
| Every hour | Refreshes the tracking status of up to 20 labels that haven't been delivered. |
| EasyPost sends a tracking update, if you add the webhook | Saves the new tracking status on the order. |
- An EasyPost account with at least one carrier account, your own or one EasyPost provides.
- A payment method in EasyPost for production labels. Labels bought with a test key aren't charged.
- Shipping weights on your products, so rates and labels have the right weight.
Install EasyPost from the Swell App Store, and set it up in your test environment before the live one.
Copy an API key
In EasyPost, go to Account Settings > API Keys and copy a key. Use the test key, which starts with EZTK, in your Swell test environment, and the production key, which starts with EZAK, in live.
Add it to the app
In Swell, go to Apps > EasyPost > Settings and enter the API key. On the Ship-from address tab, enter the address your parcels ship from: at least the street, city, postal code and country code, and the state code where carriers need it, such as in the US and Canada. Some carriers need a phone number to buy a label. On the Default parcel tab, check the box size and default weight. On the Labels tab, choose when to Buy labels. Click Save settings.
Test the connection
Choose Actions > Test connection. The message says whether EasyPost accepted the key and flags a missing ship-from address. With a production key, it also lists your carrier accounts. While Webhook secret is empty, it also suggests setting one.
Turn on checkout rates
Go to Settings > Shipping, turn on EasyPost and click Save changes. Rates appear at checkout only after this step.
Place a test order
Add an item to a cart and enter a shipping address. EasyPost rates appear among the shipping options. Choose one, then place and pay the order. If Buy labels is set to Automatically when an order is paid, the app buys the label. Otherwise, open the order and choose Actions > Buy EasyPost label. The order's EasyPost tab shows Label purchased, and the order gets a shipment with the tracking number.
Go live
Settings are saved separately for each environment. In the live environment, repeat steps 2 to 4 with your production key. If you use the webhook, add a production webhook for live, as described under Webhook for tracking updates.
When a cart's shipping address or items change, the app asks EasyPost for rates from your ship-from address to the customer's, for one parcel with the default dimensions. The weight is the sum of the items' shipping weights, or the default weight when no item has one. Each carrier service becomes a shipping option, named like USPS Priority or UPS Ground, with the estimated delivery days. The cheapest option is listed first.
- Limit the rates with Carrier accounts and Services, and add a Markup (%) and a Handling fee to each rate.
- A rate is shown only when EasyPost quotes it in the cart's currency.
- Your other shipping services, Swell's own or other apps', stay at checkout alongside EasyPost's.
By default, a label is bought only when you open an order and choose Actions > Buy EasyPost label. To buy labels automatically, set Buy labels to Automatically when an order is paid or Automatically when an order is submitted. Automatic labels are charged to your EasyPost account as soon as the order is paid or submitted.
To buy a label, the app creates an EasyPost shipment with the shipping and ship-from addresses, one parcel with the default dimensions, and the order number as the reference. Label service decides which rate it buys:
- Service the customer chose, else the cheapest: the EasyPost service the customer chose at checkout, from the cheapest carrier account that offers it, as at checkout. If EasyPost no longer offers it, or the order was shipped with another shipping service, the cheapest rate.
- Only the service the customer chose: the EasyPost service the customer chose. If it isn't offered, or the order was shipped with another shipping service, no label is bought.
- Always the cheapest: the cheapest rate, whatever the customer chose.
The cheapest rate is chosen among the services allowed by Services. The label costs EasyPost's price at the time it's bought, without your markup or handling fee, and the order's EasyPost tab shows it as Postage.
After buying, the app creates a Swell shipment for everything still to ship, with the carrier, service and tracking number, and saves the label link and tracking number on the order's EasyPost tab. With Create Swell shipment when a label is bought off, the label and tracking are saved on the tab but the order isn't fulfilled.
Canceled orders, orders with nothing to ship and orders that already have a label are skipped. If a purchase is interrupted after EasyPost bought the label, the next try uses that label instead of buying another.
If buying fails, the order's EasyPost tab shows Error with the reason. When EasyPost has a server error or doesn't answer in time, Swell tries an automatic purchase again. Other errors, such as an invalid address or no rates, aren't retried. To try again, choose Actions > Buy EasyPost label.
When an order ships to another country than your ship-from address, its label includes a customs declaration with one line for each item: the product name, quantity, line total in the order's currency, weight and SKU. The contents type is merchandise, and an undeliverable parcel is returned. The declaration is signed with the Customs signer, or the ship-from name when it's empty.
To declare a product's HS code and Country of origin, enter them on the product's EasyPost tab. The country of origin is a 2-letter country code, such as PT. Without an HS code, none is declared, and without a country of origin, your ship-from country is used.
To void a label, open the order and choose Actions > Void EasyPost label. The app asks EasyPost to refund the label. Unless the carrier rejects the refund, the app cancels the Swell shipment it created for the label, if any, and clears the tracking, and the order shows Label voided with the Refund status, Submitted or Refunded. You can then buy a new label. When the carrier rejects the refund, the label and its Swell shipment stay, and Refund shows Rejected.
Every hour, the app refreshes up to 20 labels that haven't been delivered, those checked longest ago first. For each, it saves the tracking status, the latest scan with its location, the estimated delivery and the tracking page on the order's EasyPost tab. To refresh right away, choose Actions > Refresh tracking now in the app settings.
A label is no longer refreshed once its tracking status is Delivered, Returned to sender, Failure, Cancelled or Error, or 60 days after it was bought.
The webhook is optional. With it, EasyPost sends tracking updates as carriers scan the parcel, and the app saves them on the order right away. Without it, tracking is refreshed every hour.
Choose a webhook secret
In Apps > EasyPost > Settings, on the Webhook tab, enter a long random string as the Webhook secret and click Save settings. Keep a copy to enter in EasyPost.
Build the webhook URL
Start from the Webhook URL on the same tab:
https://{store-id}:{public-key}@{store-id}.swell.store/functions/easypost/easypost-webhookReplace {store-id}, in both places, with your store ID, the subdomain of your swell.store address, and {public-key} with a Swell public key from Developer > API keys: the test key for the test environment, the live key for live. Never use a secret key here.
Add it in EasyPost
In EasyPost, go to Account Settings > Webhooks and add a webhook with the URL and the same webhook secret. EasyPost webhooks belong to a mode: add a test webhook with the test-key URL for your test API key, and a production webhook with the live-key URL for your production key.
With a secret, the app rejects events that aren't signed with it. Without one, it accepts unsigned events. Either way, it loads the tracker from EasyPost with your API key before saving anything, so an event's content is never used as is.
| Where | What it's for |
| Apps > EasyPost > Settings | The API key, ship-from address, checkout rates, default parcel, labels and webhook settings, with Test connection and Refresh tracking now. |
| Settings > Shipping | Turns EasyPost rates at checkout on or off. |
| The order list | An EasyPost column with each order's status: Label purchased, Label voided or Error. |
| An order's EasyPost tab | The status, EasyPost shipment ID, carrier, service, tracking number, tracking status and details, estimated delivery, tracking page, label link, postage and currency, and the refund status and last error when there are any. |
| An order's Actions menu | Buy EasyPost label, or Void EasyPost label once the order has a label. |
| A product's EasyPost tab | The HS code and country of origin declared on customs forms. |
Settings are in Apps > EasyPost > Settings and are saved separately for each environment.
| Setting | Description | Default |
| API key | From EasyPost > Account Settings > API Keys. Use a test key (EZTK…) in test and a production key (EZAK…) in live. Masked on the settings page. Required. | None |
| Enabled | Turns off checkout rates, label buying, tracking and the webhook without uninstalling the app. Test connection still works. | On |
| Ship-from address | Name, company, street, street line 2, city, state or province code, postal code, 2-letter country code, phone and email. Street, city, postal code and country are needed for rates and labels. The company is used as the name when the name is empty. | None |
| Show EasyPost rates at checkout | Turns checkout rates off while labels and tracking keep working. | On |
| Carrier accounts | Optional. EasyPost carrier account IDs, starting with ca_, separated by commas. Used for rates and labels. | All carrier accounts |
| Services | Optional. Carrier and service pairs to offer, such as USPS:Priority and UPS:Ground, separated by commas. Also limits the cheapest rate for labels. | All services |
| Markup (%) | Added to each rate at checkout. | 0 |
| Handling fee | A flat amount added to each rate after the markup, in the checkout currency. | 0 |
| Show estimated delivery days | Shows the estimated delivery under each option. | On |
| Default parcel | The box size (in or cm) used for every rate and label, and the default weight (lb, oz, kg or g) used when no item has a shipping weight. | 10 × 8 × 4 in, 1 lb |
| Buy labels | Only with Buy label on the order page, Automatically when an order is paid, or Automatically when an order is submitted. Labels are charged to your EasyPost account. | Only with Buy label on the order page |
| Label service | Service the customer chose, else the cheapest; Only the service the customer chose; or Always the cheapest. | Service the customer chose, else the cheapest |
| Label format | PDF, PNG or ZPL for thermal printers. | |
| Create Swell shipment when a label is bought | Fulfills the Swell order with the carrier and tracking number. When off, the label and tracking are still saved on the EasyPost tab. | On |
| Customs signer | The name that signs customs declarations for international labels. | The ship-from name |
| Webhook secret | Optional. The secret EasyPost signs webhook events with. When set, unsigned events are rejected. Masked on the settings page. | None |
| Webhook URL | Read only. The URL pattern to add in EasyPost, with your store ID and a public key filled in. | The URL pattern |
- Rates and labels use one parcel with the default dimensions. Multi-parcel and split shipments aren't supported, and an order has one label at a time.
- Rates aren't reserved. A label costs EasyPost's price when it's bought, which can differ from the rate the customer paid.
- EasyPost has 8 seconds to return rates. If it fails or takes longer, checkout shows only your other shipping services.
- Rate requests don't include customs details, so some international rates may be missing at checkout. Labels include a customs declaration with each product's HS code and country of origin when you've entered them. If a carrier needs more, buying fails with EasyPost's error on the order.
- Canceling or changing a Swell order doesn't void its label or change the EasyPost shipment. Void the label yourself.
- Carriers refund only unused labels, within their own time limits. The refund status is saved when you void the label, and later changes in EasyPost aren't shown.
- Without the webhook, tracking can be up to an hour old, and each hourly refresh covers up to 20 labels.
- Test connection lists carrier accounts only with a production key, because EasyPost lists them only for production keys.
- Items without a shipping weight add nothing to the parcel weight.
Errors from buying a label are shown in Error on the order's EasyPost tab, and actions show their result in a message. The app also logs its errors. In the Swell dashboard, the logs are under Developer > Console > Logs.
Check that EasyPost is turned on in Settings > Shipping and saved, that Show EasyPost rates at checkout and Enabled are on, and that the ship-from address has a street, city, postal code and country code. Rates in another currency than the cart's, and services not listed in Services, aren't shown. Run Test connection to check the key. With a production key, it also lists your carrier accounts.
Check that Buy labels is set to buy automatically when the order is paid, or submitted, and that Enabled is on. Canceled orders and orders with nothing to ship are skipped. If buying failed, the reason is in Error on the order's EasyPost tab. To try again, choose Actions > Buy EasyPost label.
Enter the street, city, postal code and country code on the Ship-from address tab of the app settings, click Save settings, and buy the label again.
The order has no shipping country. Add the shipping address to the order, then choose Actions > Buy EasyPost label.
Label service is set to Only the service the customer chose, and the customer chose another shipping service. To buy the cheapest EasyPost rate for these orders, set Label service to Service the customer chose, else the cheapest.
EasyPost didn't quote the customer's service when the label was bought, for example after your carrier accounts changed. To buy the cheapest rate instead, set Label service to Service the customer chose, else the cheapest, then choose Actions > Buy EasyPost label.
No carrier quoted the parcel, or no rate matches Services. The message also lists up to 5 carrier messages from EasyPost. Check the addresses, the default parcel, the items' weights and your carrier accounts.
EasyPost took too long. Swell tries automatic purchases again, and if EasyPost bought the label before the time ran out, the next try uses it instead of buying another. To try again yourself, choose Actions > Buy EasyPost label.
Test connection shows this when EasyPost doesn't accept the API key. Check that you copied the whole key, and that it's the test key in the test environment and the production key in live.
Carriers refund only unused labels, within their own time limits. The label and its Swell shipment stay as they are.
Wait for the next hourly refresh, or choose Actions > Refresh tracking now in the app settings. When more than 20 labels are waiting, the message says so, and you can run it again. Labels bought more than 60 days ago aren't refreshed. If you use the webhook, check that it's in the same mode, test or production, as your API key.
EasyPost's webhook gets a 401 response with this message when Webhook secret is set in Swell but the event wasn't signed with the same secret. Enter the same secret in the app settings and in the EasyPost webhook. Tracking keeps refreshing every hour in the meantime.
EasyPost's webhook gets a 404 response with this message when the URL has no public key, a key from another store, or a key for an environment where the app isn't installed. Check the {public-key} part of the URL.
Uninstalling the app removes EasyPost rates from checkout and from Settings > Shipping, stops buying labels and refreshing tracking, and removes the app's settings page, the EasyPost tab, column and order actions, and the EasyPost tab on products. The webhook stops working, so EasyPost's deliveries to it fail. Uninstalling applies to the environment you are in, so remove the app from the test and live environments separately.
The EasyPost values saved on your orders and products are kept, and come back if you reinstall the app. Labels, shipments and webhooks in your EasyPost account stay there, and Swell shipments the app created stay on your orders. If you added the webhook, delete it in EasyPost under Account Settings > Webhooks.
| Function | Runs on | What it does |
| shipping-rates | after:order.shipping, for the easypost shipping extension | Gets EasyPost rates and adds them to the shipping options. |
| easypost-order-events | order.paid and order.submitted | Buys the label on the event chosen in Buy labels. |
| refresh-tracking | Every hour | Refreshes the trackers of up to 20 labels that haven't been delivered. |
| easypost-webhook | A public POST route | Receives EasyPost tracker events and saves the tracker on its order. |
| test-connection | The Test connection action | Checks the API key and lists the carrier accounts of a production key. |
| refresh-tracking-now | The Refresh tracking now action | Runs the tracking refresh now. |
| buy-label | The Buy EasyPost label order action | Buys the label for one order. |
| void-label | The Void EasyPost label order action | Refunds the order's label and cancels the Swell shipment the app created. |
The app stores its fields on orders under $app.easypost: easypost_status, easypost_shipment_id, easypost_tracker_id, easypost_tracking_code, easypost_tracking_url, easypost_label_url, easypost_carrier, easypost_service, easypost_label_cost, easypost_label_currency, easypost_label_date, easypost_refund_status, easypost_swell_shipment_id, easypost_tracking_status, easypost_tracking_details, easypost_tracking_date, easypost_eta, easypost_checked_at and easypost_error. On products, it stores easypost_hs_code and easypost_origin_country under $app.easypost.
Rate IDs are easypost_ plus the EasyPost carrier and service in lowercase, such as easypost_usps_priority, and each option also carries easypost_carrier and easypost_service. The label step matches the order's shipping.service against these IDs and buys the cheapest of the matching rates.
Each rate request and each label creates an EasyPost shipment with POST /shipments. Labels are bought with POST /shipments/{id}/buy and voided with POST /shipments/{id}/refund, and tracking is read with GET /trackers/{id}. Weights are sent in ounces and dimensions in inches, with one decimal. Swell item weights are line totals in the store's weight unit.
A label purchase gets 5 seconds to create the shipment and 4 to buy it. The EasyPost shipment ID is saved on the order before buying, so a retry finds a label bought by an interrupted run. EasyPost server errors, timeouts and Swell errors are rethrown so the platform retries the model event. EasyPost 4xx errors are saved on the order and not retried.
Customs declarations use contents_type: merchandise, eel_pfc: NOEEI 30.37(a) and non_delivery_option: return. Each item's value is its line total with the order's currency, and hs_tariff_number and origin_country come from the product's easypost_hs_code and easypost_origin_country. Swell shipments get the EasyPost carrier in lowercase as carrier, the readable service name as service, and the EasyPost shipment ID and tracking page in notes.
Each tracking refresh reads up to 20 orders sorted by easypost_checked_at, whose easypost_label_date is in the last 60 days, or whose order date is for labels bought before that field existed, and stops starting new ones after about 6 seconds. Tracker updates older than easypost_tracking_date are skipped, and a tracker whose shipment isn't the order's label is ignored.
The webhook handles tracker.created and tracker.updated and acknowledges other events. With a secret, it checks X-Hmac-Signature, which is hmac-sha256-hex= plus the HMAC-SHA256 of the raw body, keyed with the secret normalized to NFKD. It answers right away, then loads the tracker with GET /trackers/{id} before saving it.
Swell builds and maintains the EasyPost app. For help with the app, email support@swell.is. For questions about your EasyPost account, carriers or labels, contact EasyPost.