Integrations / WooCommerce
WooCommerce integration guide
WooCommerce doesn’t know anything about Serian ShipKit out of the box — but because it’s a WordPress plugin, you can call our API from a tiny companion plugin or from a code snippet in functions.php. We don’t currently ship an official plugin; this guide shows you the minimum code to roll your own.
1. Get an API key
In your Serian ShipKit dashboard, go to API Keys and create one. Start with a sk_test_key while you’re developing — it never charges you. Copy it into your WordPress secrets (wp-config.php, Vault, or a secrets manager).
2. Add a shipping method that asks us for rates
Drop this into a small MU-plugin (wp-content/mu-plugins/serian.php). It registers a new shipping method that hits POST /api/v1/rates and returns the quotes to WooCommerce at checkout.
<?php
/*
* Plugin Name: Serian ShipKit Shipping
*/
add_action('woocommerce_shipping_init', function () {
class WC_Shipping_Serian extends WC_Shipping_Method {
public function __construct() {
$this->id = 'serian';
$this->method_title = 'Serian ShipKit';
$this->init();
}
public function init() {
$this->init_form_fields();
$this->init_settings();
$this->title = $this->get_option('title', 'Serian ShipKit');
}
public function calculate_shipping($package = []) {
$body = [
'shipper' => [
'name' => get_bloginfo('name'),
'street1' => get_option('serian_ship_from_street1'),
'city' => get_option('serian_ship_from_city'),
'state' => get_option('serian_ship_from_state'),
'zip' => get_option('serian_ship_from_zip'),
'country' => get_option('serian_ship_from_country', 'GH'),
],
'recipient' => [
'name' => $package['destination']['first_name'] ?? 'Recipient',
'street1' => $package['destination']['address_1'],
'city' => $package['destination']['city'],
'state' => $package['destination']['state'],
'zip' => $package['destination']['postcode'],
'country' => $package['destination']['country'],
],
'parcels' => [[
'length' => 20, 'width' => 15, 'height' => 10,
'weight' => 1, 'dimension_unit' => 'CM', 'weight_unit' => 'KG',
]],
];
$res = wp_remote_post('https://api.serianshipkit.com/api/v1/rates', [
'headers' => [
'Authorization' => 'Bearer ' . SERIAN_API_KEY,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode($body),
'timeout' => 10,
]);
if (is_wp_error($res)) return;
$data = json_decode(wp_remote_retrieve_body($res), true);
foreach (($data['rates'] ?? []) as $rate) {
$this->add_rate([
'id' => 'serian_' . $rate['service_type'],
'label' => $rate['service_name'],
'cost' => $rate['total_charge'],
'meta_data' => [ 'serian_rate_id' => $rate['rate_id'] ],
]);
}
}
}
});
add_filter('woocommerce_shipping_methods', fn($m) => $m + ['serian' => 'WC_Shipping_Serian']);3. Create the label when the order is paid
Hook into woocommerce_order_status_processing (or woocommerce_payment_complete) and call POST /api/v1/shipments using the rate_idwe stored in the shipping item’s meta:
add_action('woocommerce_order_status_processing', function ($order_id) {
$order = wc_get_order($order_id);
foreach ($order->get_shipping_methods() as $item) {
$rate_id = $item->get_meta('serian_rate_id');
if (!$rate_id) continue;
$res = wp_remote_post('https://api.serianshipkit.com/api/v1/shipments', [
'headers' => [
'Authorization' => 'Bearer ' . SERIAN_API_KEY,
'Content-Type' => 'application/json',
'Idempotency-Key' => 'order-' . $order_id,
],
'body' => wp_json_encode([
'rate_id' => $rate_id,
'reference' => 'WC-' . $order_id,
]),
'timeout' => 20,
]);
$data = json_decode(wp_remote_retrieve_body($res), true);
$order->update_meta_data('_serian_tracking', $data['tracking_number']);
$order->update_meta_data('_serian_label_url', $data['label_url']);
$order->save();
}
});4. Get tracking updates back into WooCommerce
Register a webhook endpoint in your Serian ShipKit dashboard pointing at https://yourstore.com/?rest_route=/serian/v1/webhook, subscribed to tracking.updated and shipment.delivered. Verify the X-Webhook-Signature header (HMAC-SHA256 of the raw body, keyed with the webhook secret), then update the order status:
add_action('rest_api_init', function () {
register_rest_route('serian/v1', '/webhook', [
'methods' => 'POST',
'permission_callback' => '__return_true',
'callback' => function (WP_REST_Request $req) {
$raw = $req->get_body();
$sig = $req->get_header('X-Webhook-Signature');
$expected = hash_hmac('sha256', $raw, SERIAN_WEBHOOK_SECRET);
if (!hash_equals($expected, $sig)) return new WP_Error('bad_sig', '', ['status' => 401]);
$event = json_decode($raw, true);
if ($event['type'] === 'shipment.delivered') {
$orders = wc_get_orders([
'meta_key' => '_serian_tracking',
'meta_value' => $event['data']['tracking_number'],
]);
foreach ($orders as $o) $o->update_status('completed', 'Delivered by carrier');
}
return ['ok' => true];
},
]);
});Troubleshooting
- Rates never appear at checkout:check WordPress’s error log. Our API returns JSON errors with a
request_idyou can share with support. - Labels get duplicated: always pass
Idempotency-Key(we usedorder-{id}above). - Test safely: use a
sk_test_key — all labels and tracking events are simulated and never cost anything.