Batch Guide

This guide will teach you how to use Batches to create and purchase shipping labels. Batches make it simpler to create and purchase many shipping labels in just a few API calls. Even better, we group all the labels in a batch into a single file that you can download.

In this example, we will be shipping four T-Shirts to four very lucky EasyPost fans. Batches can support up to 10,000 shipments per batch.

Before You Start

  1. Sign up for an EasyPost account or log in to an existing account.
  2. Set up your webhook URLs for Test Mode and Production Mode.
  3. Grab one of our official client libraries.

If you haven't run through our Getting Started Guide, definitely do that before moving on to this one.

Step 1: Creating a Batch of Shipments

A Batch is a collection of Shipments that you purchase and generate labels for together. When creating a Batch, you can either:

  • Create and purchase the Shipment objects ahead of time and pass Shipment IDs.
  • Pass us the information needed to create Address, Parcel, and Shipment objects as well as tell us which Carrier and Service you want to use for that Shipment.

When you create a Batch, the Shipments within the Batch are created asynchronously. When you first POST to create the Batch, we will send a webhook to your app that the Batch object is being created. ("state":"creating") It will take on average 1 minute to process 1,000 Shipments.

Once all are created, we will send another webhook to your application telling you it is complete ("state":"created"). If there are any errors for the Batch object, we will tell you about them in the webhook ("state":"creation_failed"). Step 2 of this tutorial will show you how to fix any errors that arise. There is more information on webhooks later in the tutorial.

Here is an example of creating a batch by passing us all the information in one API call:

Creating a Batch

      
curl -X POST https://api.easypost.com/v2/batches \
  -u <YOUR_TEST/PRODUCTION_API_KEY>: \
  -d 'batch[shipment][0][from_address][company]=EasyPost' \
  -d 'batch[shipment][0][from_address][street1]=417 Montgomery Street' \
  -d 'batch[shipment][0][from_address][street2]=5th Floor' \
  -d 'batch[shipment][0][from_address][city]=San Francisco' \
  -d 'batch[shipment][0][from_address][state]=CA' \
  -d 'batch[shipment][0][from_address][zip]=94104' \
  -d 'batch[shipment][0][to_address][name]=Kyle Broflovski' \
  -d 'batch[shipment][0][to_address][street1]=517 Hathaway St' \
  -d 'batch[shipment][0][to_address][city]=Fairplay' \
  -d 'batch[shipment][0][to_address][state]=CO' \
  -d 'batch[shipment][0][to_address][zip]=80440' \
  -d 'batch[shipment][0][parcel][length]=8' \
  -d 'batch[shipment][0][parcel][width]=6' \
  -d 'batch[shipment][0][parcel][height]=5' \
  -d 'batch[shipment][0][parcel][weight]=10'\
  -d 'batch[shipment][0][reference]=order12345' \
  -d 'batch[shipment][0][carrier]=USPS' \
  -d 'batch[shipment][0][service]=First' \
  -d 'batch[shipment][1][from_address][name]=And So On' \
  -d 'batch[shipment][2][from_address][name]=And So On' \
  -d 'batch[shipment][3][from_address][name]=And So On' \

      
    
Batch JSON Response
{
  "id": "batch_JUy4rWef",
  "label_url": null,
  "mode": "test",
  "num_shipments": 4,
  "object": "Batch",
  "reference": null,
  "scan_form": null,
  "shipments": [  ],
  "state": "creating",
  "status": {
    "created": 0,
    "queued_for_purchase":0,
    "creation_failed":0,
    "postage_purchased": 0,
    "postage_purchase_failed": 0
  },
  "label_url": null,
  "created_at": "2014-07-22T07:34:39Z",
  "updated_at": "2014-07-22T07:34:39Z"
}

Step 2: Adding and Removing Shipments from a Batch

After you create a Batch, you can still add Shipments to it. To add Shipments to a Batch, you need to create and purchase the Shipment object ahead of time and then add it to your already existing Batch.

Here is an example:

Adding Shipments

      
curl -X POST https://api.easypost.com/v2/batches/{BATCH_ID}/add_shipments \
  -u <YOUR_TEST/PRODUCTION_API_KEY>: \
  -d 'shipments[0][id]={SHIPMENT_ID}' \
  -d 'shipments[1][id]={SHIPMENT_ID}' \
  ...

      
    
Parcel Response
{
  "created_at": "2014-07-22T07:34:39Z",
  "id": "batch_JUy4rWef",
  "label_url": null,
  "mode": "test",
  "num_shipments": 6,
  "object": "Batch",
  "reference": null,
  "scan_form": null,
  "shipments": [
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_fr34gTR5"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_YUe5r2gF"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_OIh23rTe"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_fe432kEf"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_bfJu234r"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_MJfer45t"
    }
  ],
  "state": "created",
  "status": {
    "created": 6,
    "creation_failed": 0,
    "postage_purchase_failed": 0,
    "postage_purchased": 0,
    "queued_for_purchase": 0
  },
  "updated_at": "2014-07-22T07:40:30Z"
}

There may be times when you need to remove a Shipment from a Batch. You can do that too. For example, a particular Shipment may have an invalid address but you may still want to continue on with the rest of the Shipments.

You can easily remove a Shipment from a Batch with the following code:

Removing Shipments

      
curl -X POST https://api.easypost.com/v2/batches/{BATCH_ID}/remove_shipments \
  -u <YOUR_TEST/PRODUCTION_API_KEY>: \
  -d 'shipments[0][id]={SHIPMENT_ID}' \
  -d 'shipments[1][id]={SHIPMENT_ID}' \
  ...

      
    
Removing Shipment JSON Response
{
  "created_at": "2014-07-22T07:34:39Z",
  "id": "batch_JUy4rWef",
  "label_url": null,
  "mode": "test",
  "num_shipments": 4,
  "object": "Batch",
  "reference": null,
  "scan_form": null,
  "shipments": [
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_fr34gTR5"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_YUe5r2gF"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_OIh23rTe"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_fe432kEf"
    }
  ],
  "state": "created",
  "status": {
    "created": 4,
    "creation_failed": 0,
    "postage_purchase_failed": 0,
    "postage_purchased": 0,
    "queued_for_purchase": 0
  },
  "updated_at": "2014-07-22T07:43:33Z"
}

Step 3: Creating and Purchasing Shipping labels for a Batch

The next step is to purchase and create all labels for the shipments in your batch. All you need to do is issue a buy on the particular Batch object you’re ready to buy. When you buy the batch, we kick off an asynchronous process to create all the labels you need

The initial response from buying a Batch will not have the URL of a label. Because we support up to 10,000 shipments in a Batch, it takes a little time to create all the labels. For 100 labels, it takes about 1 minute.

Once we’ve purchased and created all the labels for a batch, we’ll send a webhook to your application letting you know that it has completed. When completed, the “state” of the Batch object will be “purchased”. If there are any errors, the state of the Batch object will be "purchase_failed". You will need to fix or remove any of the shipments that failed before proceeding to the next step of creating the Batch Label.

Here's a code example of buying a Batch:

Buying a Batch

      
curl -X POST https://api.easypost.com/v2/batches/{BATCH_ID}/buy \
  -u <YOUR_TEST/PRODUCTION_API_KEY>: \

      
    
Printing Results
{
  "created_at": "2014-07-22T07:34:39Z",
  "id": "batch_JUy4rWef",
  "label_url": null,
  "mode": "test",
  "num_shipments": 4,
  "object": "Batch",
  "reference": null,
  "scan_form": null,
  "shipments": [
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_fr34gTR5"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_YUe5r2gF"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_OIh23rTe"
    },
    { "batch_message": null,
      "batch_status": "created",
      "id": "shp_fe432kEf"
    }
  ],
  "state": "purchased",
  "status": {
    "created": 0,
    "creation_failed": 0,
    "postage_purchase_failed": 0,
    "postage_purchased": 4,
    "queued_for_purchase": 0
  },
  "updated_at": "2014-07-22T07:46:42Z"
}

Step 4: Creating a Batch Label

Once you have received the webhook that your Batch has been purchased, the final step is to create and retrieve all the shipping labels in a single Batch Label. All the labels for the Batch will be in a single file that you download. A Batch Label can be retrieved in either PDF, EPL2, or ZPL format.

Here’s an example of retrieving your labels in a single PDF file:

http://assets.geteasypost.com/batches/labels/HLBD0d.pdf

Creating Batch Label

      
curl -X POST https://api.easypost.com/v2/batches/{BATCH_ID}/label \
  -u <YOUR_TEST/PRODUCTION_API_KEY>: \
  -d 'file_format=pdf' \

      
    
Creating Batch Label Response
{
  "created_at": "2014-08-04T22:20:08Z",
  "id": "batch_z2PiM6NE",
  "label_url": null,
  "mode": "test",
  "num_shipments": 4,
  "object": "Batch",
  "reference": null,
  "scan_form": null,
  "shipments": [
  { "batch_message": null,
    "batch_status": "postage_purchased",
    "id": "shp_eCSWlje2"
  }],
  "state": "label_generating",
  "status": {
    "created": 0,
    "creation_failed": 0,
    "postage_purchase_failed": 0,
    "postage_purchased": 4,
    "queued_for_purchase": 0
  },
  "updated_at": "2014-08-04T22:37:49Z"
}

You can only get shipping labels for a Batch if all Shipments in the 'postage_purchased' status. If any of your purchases are failed, you should just remove that Shipment from the Batch during the previous step.

If the Batch Label fails to create, the Batch object will return back to "purchased" state.

Step 5: Using Webhooks for a Batch

When using Batches, webhooks are useful at three points:

  • Creating a Batch (Step 1 in the tutorial)
  • Purchasing and creating labels for a Batch (Step 3 in the tutorial)
  • Creating and retrieving a Batch label (Step 4 in the tutorial)

Webhooks are required because these processes are completed asynchronously. You will receive a webhook both on the initial POST to EasyPost and once the given action has reached a final state. If there are any errors, we will pass them back in the webhook.

When evaluating Events that hit your webhook URL, you’ll know it is a Batch event because the object “type” is “Event” and the "description" is “batch.created” or "batch.updated". As part of this Event, we will also pass you back the Batch object. The value of the Event’s "result" attribute will contain the Batch object.

We recommend you evaluate the “state” of the Batch object to check if your Batch was successfully processed. If there is an error (eg “creation failed” or “purchase_failed” ), you can then inspect the individual Shipment objects we return to see which one caused the issue. Each Shipment will have a “batch_status” that will let you know which Shipment needs to be fixed. We also provide a summary of successes and failure so you know how many Shipments need attention.

Here’s an example of webhook for a Batch:

{
  "completed_urls" : [  ],
  "created_at" : "2014-07-22T07:46:44Z",
  "description" : "batch.updated",
  "id" : "evt_hIF92i5Y",
  "mode" : "test",
  "object" : "Event",
  "pending_urls" : [ "http://requestb.in/1mjemnw1" ],
  "previous_attributes" : { "state" : "label_generating" },
  "result" : {
    "created_at" : "2014-07-22T07:46:44Z",
    "id" : "batch_JUy4rWef",
    "label_url" : "http://assets.geteasypost.com/batches/labels/HLBD0d.pdf",
    "mode" : "test",
    "num_shipments" : 1,
    "object" : "Batch",
    "reference" : null,
    "scan_form" : null,
    "shipments" : [
      { "batch_message" : null,
        "batch_status" : "created",
        "id" : "shp_fr34gTR5"
      },
      { "batch_message" : null,
        "batch_status" : "created",
        "id" : "shp_YUe5r2gF"
      },
      { "batch_message" : null,
        "batch_status" : "created",
        "id" : "shp_OIh23rTe"
      },
      { "batch_message" : null,
        "batch_status" : "created",
        "id" : "shp_fe432kEf"
      }
    ],
    "state" : "label_generated",
    "status" : {
      "created" : 0,
      "creation_failed" : 0,
      "postage_purchase_failed" : 0,
      "postage_purchased" : 1,
      "queued_for_purchase" : 0
    },
    "updated_at" : "2014-08-04T22:37:52Z"
  },
  "updated_at" : "2014-08-04T22:37:51Z"
}

Congratulations! You’ve just created and purchased your first batch with EasyPost! Check out our Full Reference API Documentation.