Skip to main content
Customize the Smart Send plugin with WordPress filters and actions in your own webshop. Hooks let you adjust checkout, delivery choices and booking behavior without editing the plugin’s code. Use the metadata reference to understand stored values and the API to read pickup points, shipping methods and bookings for a WooCommerce order. Use the code snippets for ready-to-use customizations.

Filters and actions

Choose the stage that matches your customization. Each stage and hook below links to its detailed contract and example. WooCommerce and Subscriptions integration points are listed in the integration reference. $is_return is false for outbound and true for return wherever the signature includes it. A combined booking can run a callback twice, once for each direction. Events with a Booked_Shipment instead expose $shipment->is_return().
smart_send_booking_completed means Smart Send has created one shipment. It fires before the plugin saves its booking information to the WooCommerce order. Use smart_send_order_fulfilled when you need the final order-side result, including an outbound success with a return failure.
Signatures list the filter value first, followed by context arguments; → states the required return type. Actions have no useful return value. Examples are independent customizations, not a file to install in full. For complete, ready-to-use customizations, see Code snippets. Open a hook and select Description for its contract or Example for the PHP customization and usage guidance.

Checkout availability and rates

Filter · (bool $is_available, array $package, Smart_Send\Shipping_Method\Method $method) → boolRuns after the method’s shipping-class and customer-role checks. Return false to hide this Smart Send instance for the package; return the incoming value to preserve its existing restrictions. Returning true does not create a price outside the weight table. Checkout only; no booking or order updates. This example additionally limits the method to Denmark.
Filter · (bool $is_free, array $package, Smart_Send\Shipping_Method\Method $method) → boolRuns after the configured minimum/coupon condition is evaluated, when the cart weight is allowed. true selects Flat fee cost, which is not necessarily zero; false uses normal weight-price calculation. It does not override zone, role, class or weight availability. The example disables the flat-fee branch, preserving ordinary rate calculation.
Action · (Smart_Send\Shipping_Method\Method $method, array $rate) → voidRuns at the end of a Smart Send rate calculation. $rate contains id, label, cost, meta_data and package. It can run even when weight rules produced no rate, so check $method->rates before deriving an extra option. The example adds 10 in the store currency to an existing rate, before WooCommerce tax calculation. It preserves the original service metadata; it does not book a different carrier service.

Pickup points

Filter · (array $params) → arrayRuns before a nearest-point API lookup when a token is configured. Keys: carrier, country, postal_code, street (strings) and city (string or null). Return all keys. The API determines result count; trim results with smart_send_pickup_point_list. Search parameters do not rewrite the customer’s order address. This example removes surrounding postal-code whitespace.
Filter · (Smart_Send\Delivery\Pickup_Point[] $points, array $params) → Smart_Send\Delivery\Pickup_Point[]Runs after a non-empty API result has become typed points, before session caching/display. Return a reindexed list of compatible Pickup_Point objects. The plugin removes objects that do not match the lookup’s carrier/country. It does not call this filter for an empty API result. Reordering influences Select Default only when no compatible explicit customer choice exists; this is not a way to revoke an existing compatible selection.
Filter · (string $label, Smart_Send\Delivery\Pickup_Point $point) → stringRuns when a pickup label is formatted, after Dropdown format. Return plain text, not HTML or pre-escaped entities. Each renderer escapes its output. This affects display, not the point’s identity or saved address. Identity is the exact agent number together with carrier and country.
Filter · (int $seconds) → int|floatDefault: 4 seconds. Runs for both nearest-point and single-point API requests. Return a positive timeout in seconds. Increasing it can lengthen checkout waits; it does not guarantee results. The example allows six seconds.

Shipping label booking

Customize the order-page shipping methods, delivery details, colli allocations and parcel weights, recipient and order data, and the booking request. The hooks below follow the booking flow and include success and failure events. Use smart_send_delivery_details to change item allocations and smart_send_parcel_default_weight to adjust calculated parcel weights when booking.
Filter · (array $carriers, WC_Order $order, bool $is_return) → arrayRuns separately for the outbound and return service lists on the order screen. Shape: each carrier has code, name, services; each service has code, name, addons (currently an empty array). A booking method is carrier_service, for example postnord_agent. Return the filtered carrier list. The resolved selected method is always re-added if missing, even if you return []. This narrows the UI; it is not an authorization boundary. Enforce booking rules in smart_send_delivery_details. The example offers only PostNord for outbound, subject to that selected-method safeguard.
Filter · (Smart_Send\Delivery\Delivery_Details $details, WC_Order $order, bool $is_return) → Smart_Send\Delivery\Delivery_DetailsRuns once per attempted direction after stored configuration, resolved service and submitted overrides are merged, before pickup validation and booking. Return the details object. Use set_shipping_method(), set_pickup_point() or set_parcel_plan(); use clear_pickup_point() for an explicit clear in a partial details object. Throw Smart_Send\Booking\Exceptions\Booking_Exception to reject a business rule before booking. Filter changes affect this booking; they are not automatically persisted. See delivery details and persistence.
Filter · (float $weight, Smart_Send\Delivery\Parcel_Spec $spec, WC_Order $order) → floatRuns when booking each parcel without an explicit weight. Input is the combined product weight of the items and quantities allocated to that parcel, in kg, possibly zero. The filter changes the booking’s parcel weight; it does not change item allocations, the calculated weight displayed on the order page, or the saved parcel plan. Return a finite usable weight including packaging. An explicit Parcel_Spec::set_weight() or order-screen weight bypasses the filter. An allocated deleted product with unknown weight produces a validation error before the filter; provide an explicit positive parcel weight instead. There is no direction argument; the filter can run for outbound and return.
Filter · (array $shipping_address, int $order_id) → arrayRuns when reading the order’s shipping address, before phone/email fallback and conversion to receiver data. Uses WooCommerce address keys such as first_name, last_name, company, address_1, address_2, postcode, city, country, and optional phone/email. Return the complete address. The second argument is the order ID, not a WC_Order. Both directions use the same reading stage; this filter does not save the address.
Filter · (string|null $phone, WC_Order $order) → string|nullRuns after choosing shipping phone, or billing phone when shipping and billing countries match, then trimming whitespace. Return a phone number or null. No direction flag is supplied. The example removes spaces without guessing a country calling code.
Filter · (array $receiver, WC_Order $order) → arrayRuns after receiver mapping and phone/email fallback. Keys: company, name_line1, name_line2, address_line1, address_line2, postal_code, city, country (strings), phone and email (string or null). Return all keys. This is plugin-level data, not a raw HTTP payload, and it is used in either direction. The example removes accidental whitespace around a non-null email.
Filter · (array[] $items, WC_Order $order) → array[]Runs after reading one row per order line, before allocation to parcels, in either direction. Return the same identities and valid quantities; use smart_send_delivery_details to distribute them. See the item row schema. Net/tax values are discounted line totals, not unit prices. The example trims a customs description without fabricating one for a deleted product.
Filter · (array $totals, WC_Order $order) → arrayRuns after order totals have been derived and negative net/tax values clamped to zero. Return all keys in the totals schema. Later values are used as returned; preserve reconciliation and non-negative amounts. Order-level fees are included in shipment totals, whereas parcel totals contain allocated merchandise. The example logs only the currency and order total, leaving the booking values unchanged.
Filter · (string|null $freetext, WC_Order $order) → string|nullRuns when reading text for the label, in either direction. Input is the customer’s order comment when Include order comment on label is enabled, otherwise null. Return text or null; do not return HTML. This does not control WooCommerce order-history notes. The example omits customer comments from labels.
Filter · (Smart_Send\Booking\Shipment $shipment, WC_Order $order, bool $is_return) → Smart_Send\Booking\ShipmentRuns after data extraction and parcel construction, immediately before translation into the API request. Return a Shipment. Prefer earlier filters for allocation/weight rules because this is after parcel validation. The example adds an outbound-only internal reference; it does not update the order or persist delivery settings.
Action · (Smart_Send\Booking\Booked_Shipment $booked, Smart_Send\Booking\Shipment $request, WC_Order $order) → voidRuns once per successfully booked direction, after the API response is mapped and before order-side persistence or document copying. Use $booked->is_return() for direction. It does not mean the whole outbound/return run succeeded, and a document’s local copy is not ready yet. Do not throw from the listener: a shipment already exists. Use smart_send_order_fulfilled when you need stored order results.
Action · (Smart_Send\Booking\Exceptions\Booking_Exception $exception, Smart_Send\Booking\Shipment $request, WC_Order $order) → voidRuns when the booking API call throws a handled HTTP client exception, just before it is rethrown as Booking_Exception. Read getMessage(), errors() (field → message list), and response_id() (string or null). This is not an all-failures event: local allocation, pickup or delivery validation can fail before the API call. No direction boolean is provided. The example logs a response ID, without address data or field values.

Order side effects and final result

Filter · (bool $save, Smart_Send\Booking\Booked_Shipment $shipment, WC_Order $order) → boolRuns after successful booking and persistence of submitted delivery overrides, before document-copy attempts and shipment-history persistence. Defaults to Save a copy of the PDF for either direction. Return false to skip local copies. A copy failure adds a warning; the booked shipment remains fulfilled and document URLs fall back to Smart Send. The example keeps documents remote.
Filter · (string $note_html, Smart_Send\Booking\Booked_Shipment $shipment, WC_Order $order) → stringRuns after shipment history is saved, before the native order note is added. Return safe HTML/text, or '' to omit the note. Notes are saved using WC_Order::add_order_note() when the caller requests a note. WooCommerce’s history refreshes after a page reload; the Smart Send result can appear immediately. The example writes a short plain-text note for either direction.
Filter · (bool $push, Smart_Send\Booking\Booked_Shipment $shipment, WC_Order $order) → boolRuns after the order-note step, before forwarding parcel tracking to the optional WooCommerce Shipment Tracking plugin. Default: true outbound, false return. This does not create live tracking updates or install that plugin. Returning false leaves the booked shipment’s own tracking data intact. The example disables forwarding.
Filter · (string|false $status, Smart_Send\Booking\Booked_Shipment $shipment, WC_Order $order) → string|falseRuns after tracking. Return a registered WooCommerce status such as wc-completed, or false to leave the order unchanged. Default: configured Set order status after label print for outbound; false for return. Updating status can trigger WooCommerce/third-party status hooks and emails. The example prevents Smart Send from changing status for either direction.
Action · (WC_Order $order, Smart_Send\Fulfillment\Fulfillment_Result $result) → voidRuns once after all attempted directions and their order-side steps, when at least one direction was fulfilled. A total failure does not fire it. It can carry outbound success alongside return failure. Inspect get_outbound_shipment(), get_return_shipment(), shipments(), get_steps($shipment), get_order_note_id($shipment) and get_warnings($shipment). get_validation_errors($is_return) and get_error_details($is_return) describe failures. See the booked result contracts; do not assume every optional step ran.

Plugin settings

Filter · (string $host) → stringRuns when constructing the API client. Default host: https://app.smartsend.io. Return the scheme and hostname only, for example https://app.smartsend.dev; the client appends the API version path. Applies to authentication, pickup lookup and booking. Use credentials for the selected environment; a staging site alone does not change this host.
Filter · (bool $verify) → boolDefault: true. Runs when preparing WordPress HTTP request options. Keep certificate verification enabled for production and sandbox. The example explicitly preserves verification; fix an invalid server certificate or CA configuration rather than disabling verification.
Filter · (string $message, string $level, array $context) → string|null|falseRuns only for entries enabled by the plugin’s logging policy. $level is a WooCommerce log level; $context includes source (smart-send-logistics) and plugin version. Return a rewritten message, or null/false to suppress the entry. This filter cannot enable disabled entries or replace the context by returning an array. The example suppresses debug messages only.
Filter · (string $url) → stringRuns when building the Smart Send row’s configuration guide link on the WordPress plugins screen. Default: https://smartsend.io/woocommerce/configuration/. Return a URL, not HTML. It does not change the API endpoint. The example routes the link to the local Smart Send settings screen.
Filter · (string $url) → stringRuns for the support link on the WordPress plugins screen. Default: https://smartsend.io/support/. Return a URL; the renderer escapes it. The example points to a support page on your own shop; create that page before using the snippet.
Filter · (string $notice_html) → stringRuns when Smart Send displays a major-version update notice in the plugins list. Return trusted, safe HTML: the filtered result is rendered as HTML without another sanitization pass. The example appends static guidance. This is a notice hook, not a shipping/booking hook.

Data contracts

The six order-reading filters above do not receive a return flag. They read the same order data for either direction. smart_send_payload_totals and smart_send_shipment_freetext run only when item data is non-empty. Use smart_send_booking_request for a final direction-specific adjustment.
smart_send_payload_items receives these keys on each row:
smart_send_payload_totals receives floats subtotal_net_amount, subtotal_tax_amount, shipping_net_amount, shipping_tax_amount, total_net_amount, total_tax_amount, plus the string currency. Subtotal excludes shipping and includes non-shipping order fees. Ordinarily subtotal + shipping = total, separately for net and tax; clamping negative values can take precedence. Including-tax amounts are net + tax. Preserve those relationships if changing totals.

Integration reference

This background describes platform hooks used by Smart Send, not additional public Smart Send customization hooks.
The three WooCommerce-prefixed checkout hooks above are intended for customizations. The table below explains relevant platform hooks that Smart Send listens to. Their broader contracts belong to WooCommerce; replacing the Smart Send callbacks is not the supported customization route.Smart Send also uses WooCommerce’s Blocks registration and HPOS compatibility mechanisms. These registration details and the experimental Blocks data-attribute filter are implementation details; use the pickup filters above for shared behavior across checkout types.
Smart Send uses these Subscriptions filters at priority 10:Keep these filters’ return values intact when adding your own Subscriptions callbacks. This integration follows the Subscriptions 4.9+ data-copy API; a test of the hook contract is not a test of the commercial plugin’s scheduled renewal/payment engine. See compatibility.
These snippets were executed against the plugin’s real PHP value objects with isolated WordPress/WooCommerce test doubles. Checks cover plain-text labels, result order/limits, automatic versus explicit weight, colli allocation and outbound/return event results. They do not prove carrier acceptance, your other plugins’ interactions or an external system’s delivery. Verify the affected workflow on your configured test shop before deploying.

Code snippets

Use these code snippets to change how the Smart Send plugin books shipping labels, for example to add packaging weight or split heavy orders into several parcels. Each snippet uses one of the hooks above and works on its own.
Code snippets are an advanced feature for developers. A mistake in PHP code can stop your webshop from working. Test a snippet on a staging site before you add it to your live webshop.
All snippets require Smart Send for WooCommerce 9.0 or later. To add a snippet:
  1. Open the snippet below and select the Code tab.
  2. Copy the code into one of these places:
  3. Change the settings at the top of the snippet to match your webshop.
  4. Create a shipping label for a test order and check the result.
The weight booked for a parcel is the weight of the products in it. The box, filling and tape add weight too, and the carrier can charge extra when a parcel is heavier than booked. This snippet adds a fixed packaging weight to every parcel and books parcels without a product weight with a minimum weight instead of zero.A parcel weight that you enter on the order screen is booked as entered; the snippet only changes calculated weights.Settings: $packaging_weight is the weight in kg added to every parcel. $minimum_weight is the lowest weight in kg a parcel is booked with.Hook: smart_send_parcel_default_weight
Carriers send text messages to the receiver when the parcel is on its way or ready at the pickup point, and they need the phone number in international format. Customers usually type a local number such as 12 34 56 78. This snippet adds the calling code of the shipping country (+4512345678) and removes spaces, dashes and brackets.Numbers that already start with + or 00 are only cleaned up. A leading 0 is removed, so 070-123 45 67 in Sweden becomes +46701234567.Hook: smart_send_receiver_phone
Carriers have a maximum weight per parcel, typically 20 kg for pickup points and 30-35 kg for home delivery. When you create the label, this snippet distributes the order’s items over as few parcels as possible without exceeding the maximum weight. A 45 kg order is booked as three parcels without splitting it by hand.The heaviest item is placed first, and each item goes into the first parcel it fits in. A single item heavier than the maximum gets a parcel of its own, which the carrier may refuse.The snippet makes no changes when:
  • You have already split the order into parcels on the order screen.
  • All items fit in one parcel.
  • A product on the order has been deleted, so its weight is unknown.
  • The label is a return label. Set $split_return_labels to true to split return labels too.
Reset to one parcel on the order screen removes your own split, and the snippet then splits the order again. To book a heavy order as one parcel anyway, enter the parcel weight on the order screen. The booked parcels are shown under Booked shipments on the order screen.Settings: $max_parcel_weight is the maximum weight in kg of the items in one parcel. If you also use Add packaging weight to every parcel, lower $max_parcel_weight by the packaging weight.Hook: smart_send_delivery_details
Each time a shipping label is created, from the order screen or the bulk action, this snippet sends the shipment and its label to an endpoint of your own, such as a warehouse system, an ERP, a print server, Zapier or Make. The outbound label and the return label are sent as separate requests.The request body is JSON:
Request body
direction is outbound or return. label.content_base64 contains the label file, so the receiving system does not have to download it. If the plugin cannot download the file, the value is null and the receiving system uses label.url instead.The request is sent while you wait for the label, so keep the endpoint fast. A failed request never cancels the label. The error is written to the WooCommerce log with the source smart-send-snippets and added as a private note on the order.Settings: $endpoint is the URL that receives the requests.Hook: smart_send_order_fulfilled

Metadata

Smart Send stores different data on the order, its shipping items and the catalog products. The keys below describe those records; they are not interchangeable. Prefer the documented hooks and API when changing booking behavior. Use WooCommerce CRUD objects when inspecting metadata so your integration works with both HPOS and traditional order storage. For order reads and intentional updates, follow WooCommerce’s HPOS recipe book : obtain the WC_Order, use its metadata methods, and save through the object. Do not assume orders are WordPress posts.

Shipping-item configuration

These values belong to each WC_Order_Item_Shipping, not to WC_Order. WooCommerce copies them from the chosen Smart Send rate when it creates the shipping item. These are snapshots of the method’s configuration. Editing a zone’s defaults does not rewrite existing shipping items. A service chosen for one booking in the order panel also does not overwrite these values. Read them with $shipping_item->get_meta( $key, true ); use SS_SHIPPING_WC()->method_resolver() when you need the resolved booking service, including the separate mapping for WooCommerce’s native Free Shipping method.

Order configuration and booking results

Read these fields from a WC_Order obtained with wc_get_order(). Delivery configuration is managed by Smart_Send\Delivery\Order_Meta; booking results are managed by Smart_Send\Fulfillment\Shipment_IDs. Shipment IDs identify Smart Send shipments; they are not tracking numbers, PDF URLs or WordPress attachment IDs. The history contains one row per shipment, not one per colli, and does not represent live carrier events. Outbound and return are recorded separately, including when outbound succeeds but the return fails. Use SS_SHIPPING_WC()->shipment_ids()->get( $order, false ) for the latest outbound ID, true for return, or labels( $order ) for the history. The ID reader returns an empty string when no ID is stored. For the distinction between submitted values, filter changes and persistent data, see delivery details and persistence.
Known properties include agent_no, company, address_line1, address_line2, postal_code, city and country. A point may also contain id, carrier, name_line1, name_line2, distance, coordinates and opening_hours; do not assume every optional property is present. Country is an ISO 3166-1 alpha-2 code. Coordinates have latitude and longitude; opening-hour rows have day, opens and closes.Use SS_SHIPPING_WC()->order_meta()->read( $order )->get_pickup_point() for a Smart_Send\Delivery\Pickup_Point or null. The typed object supports accessors and to_array() without requiring callers to depend on every raw property. For booking changes, use smart_send_delivery_details; changing only the raw agent number is not a substitute for resolving and validating a compatible pickup point.
This example represents two units from order item 123 in one colli. That ID is local to the order; it is neither a product ID nor a variation ID.
reference and the optional item name are labels, not item identities. Quantities and order-item IDs are positive integers. Parcel_Plan::from_array() parses the canonical shape; allocation must also be checked against the current order’s item IDs and quantities. Saving through Order_Meta strips the four measurement fields to null. An empty specs list means one parcel containing all items.Do not copy this array unchanged to another order. If items or quantities change, an incompatible saved allocation requires a reset before booking. See delivery details and persistence for allocation rules and the measurements that apply only to a booking.
The Subscriptions integration excludes _ss_shipping_label_id, _ss_shipping_return_label_id and _ss_shipping_labels from renewal metadata. It preserves reusable delivery configuration and remaps parcel allocations to the renewal’s new order-item IDs. If that mapping cannot be verified, ss_shipping_order_parcels can contain an internal unmapped_subscription_plan wrapper that forces an explicit reset. This is an error marker, not a supported parcel-plan format to write._smart_send_renewal_source_item is a temporary internal product-order-item marker with order_id and item_id; the integration removes it after processing the copied items. Do not use it as a persistent integration field._wc_shipment_tracking_items belongs to WooCommerce Shipment Tracking. Smart Send uses that extension’s API for tracking and excludes copied tracking records from renewals; it does not define the extension’s metadata schema. _vc_aio_options belongs to vConnect and is read for compatibility when resolving delivery details. Neither field is a Smart Send-owned write contract.
A submitted order-screen value takes precedence over a stored value before smart_send_delivery_details runs. Following successful booking, the submitted pickup selection and parcel item allocations are saved. The submitted method, parcel weights and dimensions apply only to the current booking. Failed booking does not save those overrides. The filter’s returned object determines what is booked, but it does not itself determine what is saved.For a combined outbound/return request, the submitted parcel plan applies to both directions unless a separate return plan overrides it. A null or empty plan means one parcel with all order items. A single spec with no allocations also includes all items and can supply explicit measurements. Multiple specs require complete allocation: every order unit exactly once, positive whole quantities, and no duplicate order-item row within a spec. Unknown order-item IDs and under-/over-allocation are rejected.

Product customs information

These fields belong to a WC_Product or WC_Product_Variation, not an order or shipping item. Use wc_get_product() and the product’s get_meta() for reading. To save an intentional product-data change, use update_meta_data() followed by the product’s save(); setting a value does not determine whether it is the correct customs classification. Booking reads the current catalog values. A variation’s value takes precedence unless it is '' or null, in which case the parent product’s value is used. The plugin’s product editor supplies the fields on the main product’s Shipping tab; it does not add a separate editor for each variation. These fields are not snapshots copied onto order lines. A deleted catalog product cannot supply its customs data. See the merchant guide to customs fields.

API

Use the plugin’s API inside WordPress to read Smart Send data for an existing WC_Order. Smart Send and a supported WooCommerce version must be active. Call the examples after Smart Send initializes on init at priority 0, for example from an init callback at priority 10 or a later order hook. If you start with an order ID, load it with wc_get_order($order_id) and check that the result is a WC_Order. These reads use WooCommerce’s order and item APIs, so they work with HPOS. They do not book shipments or contact the Smart Send API. The example functions use a my_shop_ prefix; choose your own prefix in your integration.
SS_SHIPPING_WC()->order_meta()->read($order) returns Smart_Send\Delivery\Delivery_Details with the stored pickup point and parcel plan. get_pickup_point() returns a Smart_Send\Delivery\Pickup_Point or null. See the pickup point accessors for the available fields.The helper reads the saved point; it does not find nearby points or refresh its address. If no Smart Send point is stored, it also recognizes the supported vConnect pickup point metadata. An agent number stored on its own does not provide a complete pickup point object. Individual fields can be null.get_parcel_plan() on the same details object returns the saved plan or null. To distinguish a missing plan from an invalid saved allocation, use SS_SHIPPING_WC()->order_meta()->parcel_plan_error($order), which returns an explanation or null. These stored details do not resolve a shipping method; use the next example for that.
There are two different IDs to work with:
  • $order->get_shipping_methods() returns the WooCommerce shipping line items saved on the order. get_method_id() identifies the WooCommerce method, such as smart_send_shipping or free_shipping; get_instance_id() identifies the shipping-zone method instance.
  • SS_SHIPPING_WC()->method_resolver() resolves one Smart Send service ID for each direction, such as postnord_agent or postnord_returndropoff. It reads the order’s Smart Send shipping-line metadata, the current mapping for native free shipping, or supported third-party method mappings.
resolve_outbound($order) and resolve_return($order) return '' when no service can be resolved. If a Smart Send shipping line has no return method configured, resolve_return() throws Smart_Send\Booking\Exceptions\Booking_Exception; the example keeps this distinction in return_error. is_auto_return_enabled($order) reads the automatic-return setting saved on the shipping line.These are the defaults derived for the order. They do not include unsaved choices in the order screen, submitted booking overrides, or changes made by smart_send_delivery_details. They also do not tell you which service a previous shipment was actually booked with; read that from the Booked_Shipment delivered to a booking action.
SS_SHIPPING_WC()->shipment_ids() reads the shipment references saved on the order:direction is outbound or return; booked_at is an ISO 8601 UTC timestamp or null when unavailable. The plugin retains the latest 50 history rows in total across both directions. The latest ID for each direction is stored separately, so an ID can exist even when labels() is empty. A row represents one shipment, which may contain several parcels.These are saved booking references. They do not contain live carrier status, tracking links, documents or the complete Booked_Shipment. To read documents and tracking details returned by a booking, listen to smart_send_booking_completed or smart_send_order_fulfilled and use the booked result accessors. A Fulfillment_Result describes that particular run, including a possible outbound success and return failure; it is not re-created from the order history.
Pickup_Point supplies get_agent_no(), get_company(), get_address_line1(), get_address_line2(), get_postal_code(), get_city(), get_country(), get_carrier(), get_distance(), get_latitude(), get_longitude() and get_opening_hours(). Optional values can be null. Opening hours are a list of day, opens, closes rows: the day is a lowercase English weekday and times use HH:MM:SS. An empty list means unknown opening hours. to_array() gives a serializable representation; it is not permission to trust client-submitted names or addresses.
Booked_Shipment exposes get_shipment_id(), get_carrier(), get_service_code(), is_return(), get_state(), get_booked_at(), get_tracking_code(), get_tracking_url(), parcels(), documents() and codes(). Optional tracking fields can be null. label_document() returns a Shipment_Document or null; do not assume a PDF exists for every result. A document’s download_url() chooses the saved local copy when available, otherwise the Smart Send URL.Fulfillment_Result::get_steps($shipment) reports save_documents (true, false or 'failed'), order_note (boolean), tracking (whether forwarding was requested) and order_status (status or false). A tracking step does not prove that an optional third-party integration was installed or delivered an email.Use get_order_note_id($shipment) for the saved note’s integer ID or null. get_order_note($shipment) supplies note HTML for PHP consumers. The serializable to_array() instead contains an order_note object with an id, not note HTML. Its rows have direction, status (fulfilled/failed), and shipment/steps/warnings or an error. get_error_details($is_return) returns null or an array with message, response_id, fields and html; treat message as plain text and escape output appropriately.