Every persistent object supports a uniform set of management operations. This chapter defines them once and lists what each resource allows.

1. Operations matrix

The “no destroy” principle: objects that record money or a legal handover (shipments past draft, pickups, manifests, document uploads, events) are never deleted through the API. They move to a terminal status instead. Objects that are configuration (connections, apps, webhook endpoints, files, trackers) can be deleted. This flowchart shows how the principle decides what happens when you want an object gone.

2. List

GET /v1/{resources} follows chapter 00 §10. Each resource’s list filters: Range operators are gt, gte, lt and lte. user_metadata[key]=value is an exact match. system_metadata[source] and system_metadata[batch] are also filterable on every list. carrier_metadata is never filterable or searchable, because its keys are not stable.
The grammar is the Stripe Search Query Language:
  • field:"value" for exact match, field~"val" for substring match (minimum 3 characters), and field>value (also <, >=, <=) for numbers and dates.
  • AND and OR combine clauses, but they cannot be mixed in one query. - negates a clause.
  • Searchable fields: shipments allow id, status, tracking.status, carrier, purchase.service.code, tracking.number, reference, order.id, order.invoice.number, ship_to.name, ship_to.email, ship_to.address.postal_code, ship_to.address.country, ship_from.address.postal_code, handling_units.items.sku, handling_units.items.import_hs_code, created, ship_date, and user_metadata["key"]. Trackers allow status, status_detail, carrier, tracking_number, created, delivered_at, and user_metadata["key"]. Pickups allow status, carrier, date, confirmation_number, and created.
  • The response is { "object": "search_result", "data": [...], "has_more": true, "next_page": "..." }. Search results are eventually consistent, so allow up to 1 minute after a write.
This sequence shows what that lag means for a client that searches right after creating a shipment.

4. Retrieve and expand

GET /v1/{resources}/{id}?expand[]=.... A test-mode ID requested with a live key returns 404 resource_missing, with message hinting at the mode mismatch.

5. Update

POST /v1/{resources}/{id}. Partial update. null clears a field. Setting user_metadata to {} or null clears all keys, and setting user_metadata[key] to "" deletes that key. Updating an immutable field returns 400 parameter_invalid with message naming the status that froze it.

6. Delete

DELETE /v1/{resources}/{id} returns { "id", "object", "deleted": true }. A repeated delete returns 404.

7. Bulk operations (capability batches)

The result is a batch object (bat_) with status (processing, completed, completed_with_errors), counts, and results_file (JSONL, one line per item: { index, status, object | error }). Each item gets its own idempotency key, derived as {batch_id}:{index}. Batches exist because merchants buy labels in the thousands at end of day, and shipping 1,000 POSTs through a rate limiter is a bad experience. This sequence shows a batch from submission to its results file.

8. Export

This produces a file with purpose: "export" and emits file.created. It is optional (capability exports).

9. Data retention