Skip to content

Shipping rules

Shipping rules turn your shipping policy into something Ship Jay enforces. A rule says: when these conditions hold, do these actions. Rules run on every quote, whether it comes from the app, a spreadsheet, the API or an AI agent. A rate a rule removes is removed from the quote itself, so it can never be bought.

The API manages the same rules you see in Settings, Shipping rules. Reading needs rules:read. Creating, replacing and deleting need rules:write.

Call What it does
GET /rules List your rules.
POST /rules Create a rule. Returns 201 and { "id": "..." }.
PUT /rules/{id} Replace a rule. Send the full rule.
DELETE /rules/{id} Delete a rule.
{
"name": "Sign for high value parcels",
"phase": "shipment",
"priority": 100,
"enabled": true,
"stop_on_match": false,
"conditions": { "all": [ { "field": "declared_value_cents", "op": "gte", "value": 20000 } ] },
"actions": [ { "type": "require_signature" }, { "type": "set_insurance", "amount_cents": 20000 } ]
}
Field Meaning
name 1 to 80 characters.
phase shipment runs before rating. rate runs on the rates that came back.
priority 1 to 10000, default 100. Lower numbers run first.
enabled Default true.
stop_on_match When true, a rule that matches ends its phase. Later rules in that phase are skipped.
conditions A group, { "all": [...] } or { "any": [...] }. Groups can nest. Default is { "all": [] }, which always matches. An empty any never matches.
actions 1 to 10 actions. Which ones are allowed depends on the phase.

A condition compares a field to a value. Text comparisons ignore case and surrounding spaces.

Field Type Phases
to.country text, two letter code shipment, rate
to.state text shipment, rate
to.zip text shipment, rate
international true or false, true when the country is not US shipment, rate
weight_oz number shipment, rate
packaging_type text shipment, rate
declared_value_cents number, the larger of the insurance amount and the customs value shipment, rate
reference1 text shipment, rate
rate.carrier text rate only
rate.service text rate only
rate.price_cents number rate only
rate.days number, estimated delivery days rate only

A shipment rule that uses a rate. field is rejected with 422.

Operator Meaning
eq, neq equals, does not equal
gt, gte, lt, lte numeric comparisons
in, not_in the value is in, or not in, a list. Send value as an array of up to 50 entries.
starts_with, contains text comparisons

If a rate has no estimated delivery time, rate.days has no value and the condition only holds for neq and not_in.

Shipment phase

Action Effect
{ "type": "block", "message": "..." } The quote fails with 422 and your message. details.blockedByRule is true.
{ "type": "require_signature" } Turns on signature on delivery.
{ "type": "set_insurance", "amount_cents": 20000 } Insures the parcel. Between 100 and 500000 cents. The highest amount among matching rules wins.

Rate phase

Action Effect
{ "type": "exclude_carrier", "carrier": "UPS" } Removes rates from that carrier.
{ "type": "exclude_service", "contains": "Express" } Removes rates whose service name contains the text.
{ "type": "max_price", "cents": 3000 } Removes rates above that price.
{ "type": "max_days", "days": 5 } Removes rates estimated to take longer. Rates with no estimate stay.
{ "type": "choose_rate", "strategy": "cheapest" } Picks a rate and returns it as suggested_rate_id. Strategies: cheapest, fastest, best (a balance of price and speed). Add "carrier" to pick only from one carrier.

In rate rules, the conditions are tested against each rate. choose_rate chooses among the rates that match the conditions and survived earlier removals. The first rule to choose wins, and the chosen rate gets the rule badge. A rule that chooses a rate does not buy it. Your code still has to call buy.

Goal: sign for and insure expensive parcels, never use UPS for parcels over 50 lb, and suggest the cheapest option that arrives within five days.

Terminal window
curl https://shipjay.com/api/v1/rules \
-H "Authorization: Bearer $SHIPJAY_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Sign for high value parcels",
"phase": "shipment",
"priority": 10,
"conditions": { "all": [ { "field": "declared_value_cents", "op": "gte", "value": 20000 } ] },
"actions": [ { "type": "require_signature" }, { "type": "set_insurance", "amount_cents": 20000 } ]
}'
curl https://shipjay.com/api/v1/rules \
-H "Authorization: Bearer $SHIPJAY_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "No UPS over 50 lb",
"phase": "rate",
"priority": 10,
"conditions": { "all": [ { "field": "weight_oz", "op": "gt", "value": 800 } ] },
"actions": [ { "type": "exclude_carrier", "carrier": "UPS" } ]
}'
curl https://shipjay.com/api/v1/rules \
-H "Authorization: Bearer $SHIPJAY_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Cheapest within five days",
"phase": "rate",
"priority": 50,
"conditions": { "all": [ { "field": "rate.days", "op": "lte", "value": 5 } ] },
"actions": [ { "type": "choose_rate", "strategy": "cheapest" } ]
}'

Quote a 60 lb parcel after this and the UPS rates are gone. applied_rules in the quote response lists each rule that did something, with its effects, and suggested_by_rule names the rule that chose a rate.

© 2026 Ship Jay. All rights reserved. Created & Developed by WCWS Internet