Add shipping insurance

Quote package protection with the SDK, then register the policy with one server-to-server call.

Shipping insurance on the custom path works like warranties do: the browser SDK quotes and displays the offer, and your server makes the call that creates the policy when the order is placed. For what shipping insurance covers and how the premium works, see Shipping Insurance.

Four pieces make it work:

  1. Quote and show the offer (browser, SDK). Fetch a quote for the cart subtotal and render the Package Protection widget. When the customer opts in, you add the premium to your own cart as a line item.
  2. Register the policy (server, REST). When the order is placed, POST it — including the quote's offerId — to POST /api/v2/shipping-insurance/orders. This is what creates the policy.
  3. Report the shipment (server, REST). Send the tracking number when the order ships.
  4. Report a cancellation (server, REST) if the order is cancelled.

Registering the policy is what creates it

Charging the customer the premium does not insure anything by itself. Treat a successful POST /api/v2/shipping-insurance/orders response as the definition of "the policy exists" — if the call fails, retry it or flag the order for follow-up.

Prerequisites

  1. The SDK is loaded and initialized with your public token. See Initialize the SDK.
  2. Shipping insurance is enabled on your Mulberry account by the Mulberry team, including your customer rate. Contact your account manager if you're not sure.
  3. Your server has your API token for the registration and lifecycle calls — the same credential split as Register the sale: public token in the browser, API token server-side only.

Quote and show the offer

After mulberry.core.initCompleted resolves, the SDK exposes mulberry.shippingInsurance:

await window.mulberry.core.init({ publicToken: "<your-public-token>" });

if (window.mulberry.shippingInsurance.isEnabled()) {
  const offer = await window.mulberry.shippingInsurance.getOffer({
    cartSubtotal: "100.00",
  });

  const widget = await window.mulberry.shippingInsurance.render({
    offer,
    selector: ".shipping-insurance-slot",
    placement: "cart",
    onToggle: (selected, offer) => {
      // Add or remove the premium as a line item in YOUR cart.
      // Mulberry never touches your cart — this is your code.
    },
  });
}
  • isEnabled()true once init has completed, shipping insurance is enabled on your account, and the shopper's location is eligible. Check it before quoting.
  • getOffer({ cartSubtotal }) — quotes cartSubtotal × your customer rate and returns { offerId, premium, cartSubtotal } (all strings). Pass the product subtotal only — no shipping, tax, or the premium itself.
  • render({ offer, selector, placement, onToggle }) — renders the Package Protection card (title, description, terms link, checkbox) into your selector element, inheriting its font and text color. placement picks between two copy slots, "cart" (default) and "shipping_options" — the names describe where a checkout typically offers protection, but they're just independently configured wording variants; use the slot whose copy Mulberry set up for where your card sits. onToggle(selected, offer) fires on every checkbox change — this is where you add or remove the premium line in your cart.
  • The returned widget instance has update(offer) and destroy().

You should now see the Package Protection card inside your selector element — the title with the premium, a short description with a terms link, and a checkbox. If nothing rendered, check the browser console: every failure logs its reason there.

When the cart changes, quote again and refresh the widget:

const fresh = await window.mulberry.shippingInsurance.getOffer({ cartSubtotal: newSubtotal });
widget.update(fresh);

Register with the latest offerId. A quote is valid for 24 hours and each offerId can create one policy; superseded quotes simply go unused.

📘

On failure, the SDK returns null

getOffer and render never throw — they log the reason to the browser console and return null (SDK not initialized, shipping insurance not enabled, invalid subtotal, selector not found). Code defensively: if getOffer returns null, don't show the offer.

Register the policy

When the order is placed with protection selected, your server makes one call:

POST https://www.getmulberry.com/api/v2/shipping-insurance/orders
Authorization: Bearer <your-api-token>
Content-Type: application/json

(Use https://staging.getmulberry.com against staging.)

FieldTypeRequiredNotes
external_order_idstringYesYour order id. Also the idempotency key — retries with the same id are safe.
offer_idstringYesThe offerId from the quote the customer accepted.
premiumdecimalYesWhat the customer paid for protection. Must match the quote exactly.
order_items_subtotaldecimalYesProduct subtotal including the premium line — see the warning below.
order_shippingdecimalYesShipping charged. Send 0 if none.
order_taxdecimalYesTax charged. Send 0 if none.
customerobjectNoemail (required within the object), first_name, last_name, phone, billing address fields. Strongly recommended — the customer receives the confirmation email and is who files claims.

order_items_subtotal includes the premium

Send the order's product subtotal as charged, with the protection line still in it — Mulberry subtracts the premium on its side. Sending a premium-exclusive subtotal under-insures the order by exactly the premium, and fails outright when the subtotal is at or below the premium.

Responses

  • 201 Created{"policy_uuid": "...", "insured_value": "111.11"}. The policy exists.
  • 200 OK — replay of an external_order_id you already registered; returns the original policy_uuid. Retries are safe.
StatusBodyMeaning
400{"error": "Invalid payload", "errors": {...}}Missing or malformed fields; errors maps each field to its problem.
400{"error": "Invalid offer token: expired"}The quote is older than 24 hours — quote again next time; this order needs Mulberry support.
400{"error": "premium does not match the quoted offer"}The premium you sent isn't the one this offer_id quoted.
400{"error": "Shipping insurance not configured for this retailer"}Not enabled on your account.
409{"error": "Offer token already used"}This offer_id already created a policy for a different order. Each quote registers once.
401Wrong or missing token. This endpoint takes the API token, not the public token.

The insured value is derived by Mulberry, not sent by you. From your breakdown and the signed quote: the products (net of premium) are covered up to the quoted subtotal, and shipping + tax on top, also capped at the quoted subtotal. Example: a $100.00 quote at a 2% rate → premium $2.00; registering order_items_subtotal 102.00, order_shipping 5.00, order_tax 6.11 insures $111.11. Because coverage is capped at the quoted basis, always register with a fresh quote for the final cart — a stale, smaller quote caps what the customer is covered for.

All amounts are plain decimal strings in your account's configured currency; there is no currency field.

Report the shipment

When the order ships, send the tracking so the shipment is registered with the insurer:

POST https://www.getmulberry.com/api/v2/shipping-insurance/shipments
Authorization: Bearer <your-api-token>
FieldRequiredNotes
policy_uuid or external_order_idOne of the twoIdentifies the policy.
tracking_numberYes
carrierYesCarrier name, e.g. "UPS".
shipment_dateYesAny common date format.
destination_addressRecommendedaddress1, city, state, postal_code, country. Registered with the insurer as the shipment's destination — omit it and the shipment is on file with no address.
customerRecommendedfirst_name, last_name, email, full_name. Registered with the insurer as the insured party.

origin_address and shipping_cost are also accepted. 200 returns {"status": "Recorded", ...} with the insurer's shipment id. Retrying is safe: re-sending an already-recorded shipment replays 200 with the same stored result (if a claim has since been filed, status reads "Claimed").

One policy covers one shipment: sending a different tracking_number for an already-recorded policy returns 409, so on a multi-package order only the first recorded package is insured.

Report a cancellation

If the order is cancelled, void the policy:

POST https://www.getmulberry.com/api/v2/shipping-insurance/cancellations
Authorization: Bearer <your-api-token>

Send policy_uuid or external_order_id, plus an optional reason. 200 returns {"status": "Voided"} — including when the policy is already voided, so this call is safe to repeat.

If the order is cancelled before it ships, there's nothing to void: no shipment was registered with the insurer, the policy simply never activates, and the call returns 409 Cannot void a policy in Pending state. That response is expected in this flow — don't retry it.

Next

Test the full loop — quote, opt in, register, ship — against staging before going live: Test and go live.