Calculate the product and shipping total for a set of items, with no added platform, card-processing or seasonal peak-postage fee. Does not create an order or charge anything. Priced through the same facility routing POST /order uses, so the estimate consults the catalog of the facility that would actually produce and charge the order (a sticker estimates at the flat-goods facility, a tee at the apparel facility). When no configured facility can produce the items, a live key gets 503 provider_unavailable — the same answer the order would give — and a test key gets a $0 breakdown flagged pricing_degraded: "provider_unavailable", matching the sandbox order path. This prices our own facilities' lanes, which ship to US addresses only: a destination_country other than US is refused 422 destination_unavailable, as the order would refuse it.
- Credential
- An API key in
x-api-key - Scopes
pricing:read
Parameters
Idempotency-Keyheader · string (uuid)Unique key for idempotent requests. If you retry a request with the same key within 24 hours, you receive the original response. The key is bound to the request payload: reusing it for a different payload returns 422
idempotency_key_reuserather than the original response, so a changed request is never silently dropped. The binding is over the JSON's content, not its bytes — keys in another order or other whitespace are the same request. Generate a new key for each new request. On an operation that moves money (an order, a batch, an item, a shipping or address change, a cancellation's refund), a key that cannot be checked because the idempotency ledger is unreachable is answered 503idempotency_unavailablewithRetry-After, and nothing runs or is charged: retry with the same key.
Request body application/json, required
itemsobject[]requiredAt most 100 lines of at most 10,000 units each, the bounds POST /order takes.
1 to 100 entries
items[].skustringrequirednon-empty
items[].quantityintegerrequired1 to 10000
shipping_methodstringOne of
standardpriorityexpressletterDefault standard
destination_countrystringISO-3166-1 alpha-2. Optional. This estimate prices our own facilities' lanes, which ship to US addresses only, so any other country is refused 422 destination_unavailable.
exactly 2 characters
Request
POST /api/v1/pricing/estimate
curl -X POST "https://printedsimply.com/api/v1/pricing/estimate" \
-H "x-api-key: ps_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: estimate-pricing-$(date +%s)" \
-d '{
"items": [
{
"sku": "sticker-die-cut-3x3",
"quantity": 100
}
],
"shipping_method": "standard"
}'Response 200
Pricing breakdown
data
fulfillment_policyobjectOptional exact-five approved fulfillment disclosure. Applies only to the four listed double-sided flags and one Santa hat, each a separate quantity-1 US standard order. Actual manufacturing expense and contribution remain unknown; the shipping benchmark includes packing. Supplies no live mapping by itself.
fulfillment_policy.fulfillment_cost_basisstringrequiredApproved per-size US standard shipping benchmark; actual postage, manufacturing cost and profit remain unknown.
Always
approved_size_shipping_benchmarkfulfillment_policy.goods_cost_centsanyrequiredActual manufacturing cost is unknown, never represented by zero.
fulfillment_policy.manufacturing_cost_centsanyrequiredfulfillment_policy.actual_contribution_centsanyrequiredfulfillment_policy.maximum_quantityintegerrequiredOne product, one SKU, quantity 1 in its own order.
Always
1fulfillment_policy.shipping_constraintsobjectrequiredfulfillment_policy.shipping_constraints.destination_countrystringrequiredAlways
USfulfillment_policy.shipping_constraints.methodstringrequiredAlways
standardfulfillment_policy.shipping_constraints.separate_orderbooleanrequiredAlways
truefulfillment_policy.shipping_benchmark_centsintegerrequiredThe approved quantity-1 US standard benchmark, packing included.
at least 0
fulfillment_policy.packagingstringrequiredAlways
included_in_shipping_benchmarkfulfillment_policy.artwork_layoutstringrequiredAlways
prepared_combined_allfulfillment_policy.artwork_instructionsstringrequiredPrepare one combined ALL PNG: flag front and back, or Santa hat front and band, according to the exact guide; remove guide lines.
fulfillment_policy.artwork_guide_urlstringrequiredLocal path to the layout guide SVG. This reference is not customer artwork and must not be sent as print_file.
itemsstringrequiredItem subtotal (e.g. '$25.00')
pricing_degradedstringPresent only when the estimate could not be priced. The figures above are then an absence of a price, not a price of zero. Never present on a live estimate — those answer 503.
One of
provider_unavailablepricing_unavailablelanded_costobjectDuty and tax for a cross-border destination. Not returned today: this estimate prices our own lanes, which ship to US addresses only, so a non-US
destination_countryis refused 422 destination_unavailable and a US one has nothing at the border. Kept in the shape for when our own lanes ship abroad.landed_cost.destination_countrystringlanded_cost.duty_basisstringOne of
DDPDAPlanded_cost.duty_ratenumberlanded_cost.tax_ratenumberlanded_cost.breakdownobjectlanded_cost.breakdown.goods_centsintegerlanded_cost.breakdown.shipping_centsintegerlanded_cost.breakdown.duties_centsintegerlanded_cost.breakdown.tax_centsintegerlanded_cost.total_landed_centsintegerlanded_cost.pre_collected_centsintegerlanded_cost.due_on_delivery_centsintegerlanded_cost.presentmentobjectThe same total in the buyer's own currency.
landed_cost.presentment.currencystringlanded_cost.presentment.amount_centsintegerlanded_cost.presentment.minor_unitsintegerlanded_cost.presentment.fx_ratenumbershippingstringrequiredprocessing_feestringrequiredCompatibility field for platform and card-processing surcharges. Zero on orders priced under the current no-added-fees policy; retained on historical records.
platform_feestringThe platform fee as a line of its own. Always 0: there is no platform fee on any order, on any plan (since 2026-10-17). Kept so a client that reads it still parses.
card_feestringCard processing on everything else the order is charged, passed through at cost.
totalstringrequiredtotal_centsintegerrequired
meta
pageintegertotalintegerlimitintegerThe page size actually applied, which is not necessarily the one asked for — the operation's own ceiling wins.
pagesintegertotaloverlimit, rounded up.next_cursorstring | nullOn a cursor-paged operation: send this back as
cursorfor the next page. Null on the last page. Absent on operations that do not page by cursor.has_morebooleanOn a list operation whose
metaisListMeta: whether another page follows this one.
{
"status": "success",
"data": {
"items": "$70.00",
"shipping": "$8.99",
"processing_fee": "$0.00",
"platform_fee": "$0.00",
"card_fee": "$0.00",
"total": "$78.99",
"total_cents": 7899
},
"request_id": "4e3753e1-48dd-4313-bfd8-48e4af4e116a"
}Errors
Invalid request body or parameters. When the request failed the operation's schema,
detailscarriesformErrors(problems with the request as a whole),fieldErrors(messages keyed by top-level field) anderrors: one{ pointer, code, message }per refused value,pointeran RFC 6901 JSON pointer into the body (or into the object of query parameters, for a query parameter) —/items/0/sku, with~written~0and/written~1, and""for the request as a whole. POST /v1/orders/bulk answerserrorsas one{ index, details }per refused order, eachdetailswith its own pointers from the request body (/orders/3/items/0/sku); POST /v1/orders/multi-ship keepserrorsas the{ formErrors, fieldErrors }it always published; POST /v1/mockups/generate and POST /v1/products/recommend keep their fields at the top ofdetails, witherrorsbeside them. A refusal of a rule the schema cannot state (an asset that does not exist, an expiry too soon) names it inmessageand carries noerrors.Missing, invalid or expired API key:
missing_api_key(none sent),invalid_api_key(unknown or revoked),key_expired(past the expiry set when it was created; create a new key).payload_too_large — the request body exceeded this route's byte cap (256 KB unless the route raises it with a written reason). It is refused before it is parsed, so nothing was created. Send fewer rows, or use the endpoint's own asynchronous door where it has one.
422destination_unavailablebelow_cost_floorsku_not_orderable_yetsku_not_availablecatalog_onlyshipment_capacity_exceededdestination_unavailable — the destination is outside the US, and this estimate prices our own lanes only: our own facilities ship to US addresses only.
details.reasonisdestination_not_usanddetails.countrynames the destination. below_cost_floor — the order would be made at our own plant and would cost more to make and ship than it is charged, at worst-case postage, and its loss is not one our cost floor accepts: only today's named losses are, no larger than they are today — the flat standard parcel under its postage, for a mailer up to a pound or a poster tube up to two, and list-priced goods short only of the per-order handling cost (or a partner SKU would be charged below what the partner bills for it).details.skusnames the items anddetails.contribution_centshow far below zero the order falls. Nothing was charged; add units, combine it with another order, or choose another shipping method on offer. sku_not_orderable_yet — live keys only: a line names a modeled product our catalog lists that our plant has not confirmed it makes yet.details.skusnames them as sent, anddetails.plant_skusthe spelling our plant adopts for one sent another way. Refused before anything is asked of the plant or charged; a test key orders a modeled listing at its listed price. catalog_only — a flag or Santa hat is a catalog reference whose artwork, production cost and shipping weight are unconfirmed. Automatic quotes and orders are refused in both test and live mode before pricing, routing or charging, including requests carrying an earlier quote;details.skus,details.readinessanddetails.reasonexplain the refusal. shipment_capacity_exceeded — a basket of sized own-plant products exceeds the modeled 70 lb single-parcel limit, including stickers, magnets, posters, decals, packs and rolls. Both test and live requests are refused before charging;details.skus,details.weight_ozanddetails.max_weight_ozstate the affected SKUs, whole-basket estimated weight and limit. Reduce the quantity or split the order. sku_not_available — a line names a product our own plant does not make: only PrintedSimply's own products (stickers, decals, labels, magnets and posters, as GET /products lists them) are sold here.details.skusnames each one. Asked before anything is priced, so nothing was priced or charged.Rate limit exceeded. Two windows can produce this status and
error.codesays which:rate_limit_exceededfor the per-minute sliding window,daily_quota_exceededfor the plan's daily quota. Both carryRetry-After; the daily one also carriesX-Daily-LimitandX-Daily-Remaining. The per-minute limits are plan-based — see Rate Limits above, or call GET /v1/me for this credential's own figures.provider_unavailable — no configured facility can produce these items, or (
details.reason: plant_unreachable, withRetry-After) our plant gave no answer about a SKU — the request did not reach it, timed out, or came back 5xx, which is about the plant and not the SKU. Live keys; a test key gets a $0 estimate flaggedpricing_degradedinstead (provider_unavailablefor an unconfigured facility,pricing_unavailablefor an unanswering plant). Only for a SKU the catalog has, though: one the price book does not price, our plant's products do not name and the synced catalog does not hold is refused 400 unknown_sku withdetails.skus, as it is on POST /order, POST /orders/quote and POST /pricing/estimate alike.