Buy labels and track parcels across hundreds of carriers worldwide through AfterShip Shipping. You connect your own carrier accounts in AfterShip, and BWH Shipping rate-shops across them.
Before you start
- An AfterShip account with Shipping and Tracking, and at least one carrier account connected
- An API key. Sandbox and production keys are different.
Set up AfterShip
1. Fill in AfterShip Shipping Settings
| Field | Value |
|---|---|
| API Key | Your AfterShip API key, matching Test Mode |
| Test Mode | On by default: labels are bought on the sandbox host. Tracking always uses AfterShip's live Tracking host, which has no sandbox. Untick it to go live. |
| Shipper Account ID | Optional. Leave it blank to rate-shop every carrier account on the key. |
| Pickup Address | An ERPNext Address to ship from. Checkout quotes from it. |
| Currency | Used when a rate has no currency |
| Volumetric Divisor | 5000, unless your carriers say otherwise |
| Rates Timeout (seconds) | How long checkout waits for rates. Default: 10. |
| Webhook Secret | The signing secret from AfterShip's webhook settings. See step 3. |
The host and API-version fields are pre-filled. Leave them alone unless AfterShip tells you otherwise.
2. Create a Shipping Provider Profile named AfterShip, set Provider Settings to AfterShip Shipping Settings, and tick Enabled.
3. Add the webhook in AfterShip's Tracking webhook settings:
- URL:
https://your.site/api/v2/method/bwh_shipping.bwh_shipping.webhook.handle?provider=AfterShip
Copy the webhook's signing secret into Webhook Secret.
4. Import Shipping Services. In the Shipping Service list, click Import from Carrier and pick services from your connected accounts. It needs an enabled profile and a Pickup Address with a country. Each service's code has the form <shipper account id>|<service type>.
To check your key, run this in bench console:
frappe.get_single("AfterShip Shipping Settings").test_connection()
How it behaves
- Rates come from every connected account, or from Shipper Account ID if you set it. Services without a price are dropped.
- Cash on delivery isn't supported. COD carts still get AfterShip rates, and a COD shipment is booked as a prepaid label. Don't offer AfterShip services for COD orders.
- Booking buys the label in one call, then registers the parcel for tracking. If registering tracking fails, the label is still kept.
- Tracking needs that registration. A shipment without it reports no status.
- Cancelling cancels the label.
- Pickups and manifests aren't available through AfterShip.
| AfterShip tag | Shipping Request status |
|---|---|
| Pending, InfoReceived | Ready To Ship |
| InTransit | In Transit |
| OutForDelivery, AvailableForPickup | Out For Delivery |
| AttemptFail | Undelivered |
| Delivered | Delivered |
Exception and Expired are ignored, so the status stays as it was. On Sync Status, their checkpoints are still added as tracking events.
Good to know
- Webhooks are signed with HMAC-SHA256, in the
Aftership-Hmac-Sha256header, and each delivery is checked against Webhook Secret. - Countries are sent to AfterShip as ISO alpha-3 codes, converted with
pycountry, which ships with Frappe. - Enabled in these settings isn't used. The profile's Enabled switches the carrier on.
- Addresses are sent as residential.
Next steps
- Use it in your app: quote at checkout and book shipments
- Webhooks and security: debug a delivery that isn't arriving