Batch
The Batch object allows you to perform operations on multiple Shipments at once.
This includes scheduling a Pickup, creating a ScanForm, and consolidating labels.
Operations performed on Batches are asynchronous and take advantage of our webhook infrastructure.
The overall state. Possible values:
- "creating"
- "creation_failed"
- "created"
- "purchasing"
- "purchase_failed"
- "purchased"
- "label_generating"
- "label_generated"
A map of statuses to the count of BatchShipment objects with that status. Valid statuses:
- "postage_purchased"
- "postage_purchase_failed"
- "queued_for_purchase"
- "creation_failed"
Batch was createdBatch was last updated{
"id": "batch_b148b3715785487597be3f3c56f04884",
"object": "Batch",
"mode": "test",
"state": "creating",
"num_shipments": 1,
"reference": null,
"created_at": "2025-05-09T20:38:21Z",
"updated_at": "2025-05-09T20:38:21Z",
"scan_form": null,
"shipments": [],
"status": {
"created": 0,
"queued_for_purchase": 0,
"creation_failed": 0,
"postage_purchased": 0,
"postage_purchase_failed": 0
},
"pickup": null,
"label_url": null
}{
"batch_status": "created",
"batch_message": null,
"reference": null,
"tracking_code": null,
"id": "shp_309a07be648b4df59ee7a85a2c2ed64f"
}A Batch can be created with or without Shipments.
When created with Shipments, the initial state will be "creating".
Once the state changes to "created", a webhook Event will be sent.
When created with no Shipments, the initial state will be "created" and webhook will be sent.
Note: It is recommended to keep each batch under 1,000 shipments. This best practice helps avoid timeout errors during the batch buying process.
1curl -X POST https://api.easypost.com/v2/batches \
2 -u "EASYPOST_API_KEY": \
3 -H 'Content-Type: application/json' \
4 -d '{
5 "batch": {
6 "shipments": [
7 {
8 "id": "shp_..."
9 },
10 {
11 "id": "shp_..."
12 }
13 ]
14 }
15 }'1{
2 "id": "batch_b148b3715785487597be3f3c56f04884",
3 "object": "Batch",
4 "mode": "test",
5 "state": "creating",
6 "num_shipments": 1,
7 "reference": null,
8 "created_at": "2025-05-09T20:38:21Z",
9 "updated_at": "2025-05-09T20:38:21Z",
10 "scan_form": null,
11 "shipments": [],
12 "status": {
13 "created": 0,
14 "queued_for_purchase": 0,
15 "creation_failed": 0,
16 "postage_purchased": 0,
17 "postage_purchase_failed": 0
18 },
19 "pickup": null,
20 "label_url": null
21}Shipments can be added to a Batch throughout its life cycle. Just remember that the
state change of a Batch is asynchronous and will fire a webhook Event when the state change
is completed.
1curl -X POST https://api.easypost.com/v2/batches/batch_.../add_shipments \
2 -u "EASYPOST_API_KEY": \
3 -H 'Content-Type: application/json' \
4 -d '{
5 "shipments": [
6 {
7 "id": "shp_..."
8 },
9 {
10 "id": "shp_..."
11 }
12 ]
13 }'1{
2 "id": "batch_6e1a3d4e645443969575c0191c047eaf",
3 "object": "Batch",
4 "mode": "test",
5 "state": "created",
6 "num_shipments": 1,
7 "reference": null,
8 "created_at": "2025-05-09T20:39:00Z",
9 "updated_at": "2025-05-09T20:39:00Z",
10 "scan_form": null,
11 "shipments": [
12 {
13 "batch_status": "postage_purchased",
14 "batch_message": null,
15 "reference": null,
16 "tracking_code": "9405500208303109884052",
17 "id": "shp_8ed3d85579c946809546e66096e3b2a3"
18 }
19 ],
20 "status": {
21 "created": 0,
22 "queued_for_purchase": 0,
23 "creation_failed": 0,
24 "postage_purchased": 1,
25 "postage_purchase_failed": 0
26 },
27 "pickup": null,
28 "label_url": null
29}There could be times when a Shipment needs to be removed from the Batch during its life cycle.
Removing a Shipment does not remove it from the consolidated label or ScanForm.
1curl -X POST https://api.easypost.com/v2/batches/batch_.../remove_shipments \
2 -u "EASYPOST_API_KEY": \
3 -H 'Content-Type: application/json' \
4 -d '{
5 "shipments": [
6 {
7 "id": "shp_..."
8 }
9 ]
10 }'1{
2 "id": "batch_19b7aa327b004c1db8dd839f727dedbf",
3 "object": "Batch",
4 "mode": "test",
5 "state": "purchased",
6 "num_shipments": 0,
7 "reference": null,
8 "created_at": "2025-05-09T20:39:02Z",
9 "updated_at": "2025-05-09T20:39:02Z",
10 "scan_form": null,
11 "shipments": [],
12 "status": {
13 "created": 0,
14 "queued_for_purchase": 0,
15 "creation_failed": 0,
16 "postage_purchased": 0,
17 "postage_purchase_failed": 0
18 },
19 "pickup": null,
20 "label_url": null
21}Once you have added all of your Shipments to a Batch, issue a buy request to enqueue a background job to purchase the shipments and generate all necessary labels.
Batch Buying Criteria: To buy a batch, all shipment data must be passed to the batch at the same time the batch is created. Each shipment of a batch must have a from_address, to_address, parcel, service, carrier, and carrier_accounts array with the single carrier account ID associated with the service.
Purchasing may take anywhere from a few seconds to an hour, depending on the size of the batch, the carrier, and Internet weather.
1curl -X POST https://api.easypost.com/v2/batches \
2 -u "EASYPOST_API_KEY": \
3 -H 'Content-Type: application/json' \
4 -d '{
5 "batch": {
6 "shipments": [
7 "from_address": {"id": "adr_..."},
8 "to_address": {"id": "adr_..."},
9 "parcel": {"id": "prcl_..."},
10 "service": "First",
11 "carrier": "USPS",
12 "carrier_accounts": ["ca_..."]
13 ]
14 }
15 }'
16
17curl -X POST https://api.easypost.com/v2/batches/batch_.../buy \
18 -u "EASYPOST_API_KEY":1{
2 "id": "batch_c050eae70c7043af941aa31cbdb92691",
3 "object": "Batch",
4 "mode": "test",
5 "state": "created",
6 "num_shipments": 1,
7 "reference": null,
8 "created_at": "2025-05-09T20:51:50Z",
9 "updated_at": "2025-05-09T20:51:50Z",
10 "scan_form": null,
11 "shipments": [
12 {
13 "batch_status": "queued_for_purchase",
14 "batch_message": null,
15 "reference": null,
16 "tracking_code": null,
17 "id": "shp_a099c1ab39a548da848bc3ad4e0f685c"
18 }
19 ],
20 "status": {
21 "created": 1,
22 "queued_for_purchase": 0,
23 "creation_failed": 0,
24 "postage_purchased": 0,
25 "postage_purchase_failed": 0
26 },
27 "pickup": null,
28 "label_url": null
29}One of the advantages of processing Shipments in batches is the ability to consolidate the PostageLabel into one file.
This can only be done once for each batch and all Shipments must have a status of "postage_purchased".
Available label formats are "PDF", "ZPL" and "EPL2". Like converting a PostageLabel format, if this process will change the format of the labels, they must have been created as PNG files.
Request Parameters
1curl -X POST https://api.easypost.com/v2/batches/batch_.../label \
2 -u "EASYPOST_API_KEY": \
3 -H 'Content-Type: application/json' \
4 -d '{
5 "file_format": "PDF"
6 }'1{
2 "id": "batch_7dd34fc685a64a5d9214ba46cc3890b0",
3 "object": "Batch",
4 "mode": "test",
5 "state": "label_generating",
6 "num_shipments": 1,
7 "reference": null,
8 "created_at": "2025-05-09T20:39:02Z",
9 "updated_at": "2025-05-09T20:39:12Z",
10 "scan_form": null,
11 "shipments": [
12 {
13 "batch_status": "postage_purchased",
14 "batch_message": null,
15 "reference": null,
16 "tracking_code": "9405500208303109884076",
17 "id": "shp_878ce5ec0135462880e2f7a840df7c69"
18 }
19 ],
20 "status": {
21 "created": 0,
22 "queued_for_purchase": 0,
23 "creation_failed": 0,
24 "postage_purchased": 1,
25 "postage_purchase_failed": 0
26 },
27 "pickup": null,
28 "label_url": null
29}A ScanForm can be created for a Batch by its id.
1curl -X POST https://api.easypost.com/v2/batches/batch_.../scan_form \
2 -u "EASYPOST_API_KEY":1{
2 "id": "batch_6cd0002c95ad4841af404b6fc8f1b7bf",
3 "object": "Batch",
4 "mode": "test",
5 "state": "created",
6 "num_shipments": 1,
7 "reference": null,
8 "created_at": "2025-05-09T20:51:07Z",
9 "updated_at": "2025-05-09T20:51:07Z",
10 "scan_form": null,
11 "shipments": [
12 {
13 "batch_status": "queued_for_purchase",
14 "batch_message": null,
15 "reference": null,
16 "tracking_code": null,
17 "id": "shp_94377a18fc63475c90e78959585b4a2c"
18 }
19 ],
20 "status": {
21 "created": 1,
22 "queued_for_purchase": 0,
23 "creation_failed": 0,
24 "postage_purchased": 0,
25 "postage_purchase_failed": 0
26 },
27 "pickup": null,
28 "label_url": null
29}A list of all Batch objects associated with the given API Key can also be retrieved.
See the Pagination section of our docs for more details on retrieving all records when multiple pages are available.
Request Parameters
after_id.before_id.end_datetime.start_datetime.asc or desc. Defaults to desc if not provided.1curl -X GET "https://api.easypost.com/v2/batches?page_size=5" \
2 -u "EASYPOST_API_KEY":1{
2 "batches": [
3 {
4 "id": "batch_5b1c3308926649c8a96c17dad1a7ace5",
5 "object": "Batch",
6 "mode": "test",
7 "state": "created",
8 "num_shipments": 1,
9 "reference": null,
10 "created_at": "2025-05-09T20:34:50Z",
11 "updated_at": "2025-05-09T20:34:50Z",
12 "scan_form": null,
13 "shipments": [
14 {
15 "batch_status": "created",
16 "batch_message": null,
17 "reference": null,
18 "tracking_code": null,
19 "id": "shp_4efcccc0f6a34dd58f83ceee58ce3adc"
20 }
21 ],
22 "status": {
23 "created": 1,
24 "queued_for_purchase": 0,
25 "creation_failed": 0,
26 "postage_purchased": 0,
27 "postage_purchase_failed": 0
28 },
29 "pickup": null,
30 "label_url": null
31 }
32 ],
33 "has_more": true
34}A Batch can be retrieved by either its id or reference.
However it is recommended to use EasyPost's provided identifiers because uniqueness on reference is not enforced.
1curl -X GET https://api.easypost.com/v2/batches/batch_... \
2 -u "EASYPOST_API_KEY":1{
2 "id": "batch_9c0d5626d0fd4b90868dbaaf4cc147cc",
3 "object": "Batch",
4 "mode": "test",
5 "state": "creating",
6 "num_shipments": 1,
7 "reference": null,
8 "created_at": "2025-05-09T20:38:21Z",
9 "updated_at": "2025-05-09T20:38:21Z",
10 "scan_form": null,
11 "shipments": [
12 {
13 "batch_status": "created",
14 "batch_message": null,
15 "reference": null,
16 "tracking_code": null,
17 "id": "shp_309a07be648b4df59ee7a85a2c2ed64f"
18 }
19 ],
20 "status": {
21 "created": 1,
22 "queued_for_purchase": 0,
23 "creation_failed": 0,
24 "postage_purchased": 0,
25 "postage_purchase_failed": 0
26 },
27 "pickup": null,
28 "label_url": null
29}