Skip to content
English
  • There are no suggestions because the search field is empty.

ReadyCloud API Shipping Integration Workflow

This document outlines the workflow for integrating with ReadyCloud’s API, including:

  1. Sending order data to ReadyCloud

  2. Configuring a webhook for order fulfillment notifications

  3. Retrieving a single order to capture tracking and shipping details

  4. Polling multiple orders to capture tracking and shipping details

Each section includes API request examples, expected responses, and best practices.

Your ReadyCloud API key and Org ID can be obtained by following the steps here:

https://kb.readycloud.com/creating-and-refreshing-an-api-token-in-readycloud-

Variables referenced throughout documentation:

Variable

Description

{YOUR_API_KEY}

ReadyCloud API Key

{org_pk}

Org ID

{order_pk}

Order ID

{box_pk}

Box ID

{item_pk}

Item ID

{item_pk}

Webhook ID

{primary_id}

Order Number

{label_image_png}

A base-64 encoded image of the label PNG

{token}

The value passed in the webhook β€œauth” header


















1. Send Order Data to ReadyCloud

To create an order in ReadyCloud, send a POST request to the /orders endpoint.

API Endpoint:

πŸ“Œ POST /orgs/{org_pk}/orders/
πŸ”—  API Documentation

Example Request:

POST https://www.readycloud.com/api/v2/orgs/{org_pk}/orders/
Content-Type: application/json
Authorization: Bearer {YOUR_API_KEY}

{
"primary_id": "1234",
"order_number": 1234,
"customer_number": "123",
"ordered_at": "2025-02-21T18:12:34Z",
"boxes": [
{
"items": [
{
"part_number": "ABC123",
"description": "Laptop",
"quantity": 1,
"unit_price": "100.00 USD",
"unit_weight": "1 lbs",
"image_link": "https://picsum.photos/id/9/512"
},
{
"part_number": "DEF456",
"description": "Keyboard",
"quantity": 1,
"unit_price": "100.00 USD",
"unit_weight": "1 lbs",
"image_link": "https://picsum.photos/id/9/512"
}
]
}
],
"custom_fields": {},
"notes": [],
"tags": [],
"source": {
"name": "Your Application",
"account": "Your Customer"
},
"shipping": {
"status": "unfulfilled",
"ship_via": "UPS Connect",
"ship_type": "UPS Ground",
"ship_to": {
"company": "",
"first_name": "Victor",
"last_name": "Ward",
"address_1": "124 RIVINGTON ST",
"address_2": "",
"city": "NEW YORK",
"region": "NY",
"post_code": "10002",
"country": "United States",
"phone": "(222) 222-2222",
"email": "victor@yourcompany.com"
},
"ship_from": {
"company": "Your Company",
"first_name": "Shipping",
"last_name": "Dept.",
"address_1": "6501 E GREENWAY PKWY",
"address_2": "",
"city": "SCOTTSDALE",
"region": "AZ",
"post_code": "85254",
"country": "United States",
"phone": "(222) 222-2222",
"email": "sales@yourcompany.com"
}
},
"billing": {
"status": "paid"
}
}

Expected Response:

{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/",
"primary_id": "1234",
"unique_id": "00003YwfHE5sdZPU9bKtT38h",
"order_number": 1234,
"customer_number": "123",
"po_number": null,
"message": null,
"terms": null,
"ordered_at": "2025-02-21T18:12:34Z",
"printed_at": null,
"updated_at": "2025-02-24T23:13:55.882339Z",
"created_at": "2025-02-24T23:13:55.881362Z",
"nested_updated_at": "2025-02-24T23:13:55.936263Z",
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}",
"items": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/box_pk}/items/{item_pk}/"
},
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
]
}
],
"custom_fields": {},
"notes": [],
"tags": [],
"relations": [],
"source": {
"name": "Your Application",
"account": "Your Customer",
"channel": null,
"retrieved_at": "2025-02-24T23:13:55.891907Z",
"updated_at": "2025-02-24T23:13:55.956006Z",
"id": null
},
"billing": {
"status": "paid",
"subtotal": null,
"shipping": null,
"tax": null,
"total": null,
"bill_to": null
},
"shipping": {
"status": "unfulfilled",
"to_ship_at": null,
"shipped_at": null,
"ship_agent": null,
"ship_via": "UPS Connect",
"ship_type": "UPS Ground",
"ship_cost": null,
"warehouse": null,
"ship_to": {
"company": "",
"first_name": "Victor",
"last_name": "Ward",
"address_1": "124 RIVINGTON ST",
"address_2": "",
"city": "NEW YORK",
"region": "NY",
"post_code": "10002",
"country": "United States",
"phone": "(222) 222-2222",
"email": "victor@yourcompany.com",
"residential": null,
"validated": false,
"updated_at": "2025-02-24T23:13:55.866898Z",
"created_at": "2025-02-24T23:13:55.866865Z"
},
"ship_from": {
"company": "Your Company",
"first_name": "Shipping",
"last_name": "Dept.",
"address_1": "6501 E GREENWAY PKWY",
"address_2": "",
"city": "SCOTTSDALE",
"region": "AZ",
"post_code": "85254",
"country": "United States",
"phone": "(222) 222-2222",
"email": "sales@yourcompany.com",
"residential": null,
"validated": false,
"updated_at": "2025-02-24T23:13:55.875870Z",
"created_at": "2025-02-24T23:13:55.875831Z"
}
}
}

Notes:

  • The primary_id should be unique.

  • The url should be stored for tracking updates from webhooks and for future polling.

Expected Result in ReadyCloud Dashboard:

You should now be able to view the order in ReadyCloud by navigating the below URL. Make sure you have already logged into ReadyCloud and then replace the {order_pk} in the below URL with the {order_pk} returned in the above API response.

https://www.readycloud.com/orders/{order_pk}

 

 
















2. Configure a Webhook for Order Fulfillment Notifications

To receive real-time notifications when an order’s shipping status changes to fulfilled, configure a webhook for the orders entity.

API Endpoint:

πŸ“Œ POST /orgs/{org_pk}/webhooks/
πŸ”—  API Documentation

Example Request:

POST https:/www.readycloud.com/api/v2/orgs/{org_pk}/webhooks/
Content-Type: application/json
Authorization: Bearer {YOUR_API_KEY}

{
"entity": "orders",
"remote_url": "https://example.com/orders/"
}

Expected Response:

{
"url": "/api/v2/orgs/{org_pk}/webhooks/{webhook_pk}/",
"remote_url": "https://example.com/orders/",
"token": "8uw7pz6qvajizvphb9p5kuf3lq1o8j",
"created_at": "2025-02-24T23:20:17.752336Z",
"updated_at": "2025-02-24T23:20:17.752357Z",
"entity": "orders",
"suspended_at": null
}

Webhook Payload Example (Verify that β€œshipping.status”: β€œfulfilled”):

PUT https://example.com/orders/{order_pk}
auth: {token}

{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/",
"primary_id": "1234",
"unique_id": "00003YwfHE5sdZPU9bKtT38h",
"order_number": 1234,
"customer_number": "123",
"po_number": null,
"message": null,
"terms": null,
"ordered_at": "2025-02-21T18:12:34Z",
"printed_at": "2025-02-24T23:42:24Z",
"updated_at": "2025-02-24T23:42:31.056522Z",
"created_at": "2025-02-24T23:13:55.881362Z",
"nested_updated_at": "2025-02-24T23:42:31.081264Z",
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}",
"items": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/box_pk}/items/{item_pk}/"
},
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
]
}
],
"custom_fields": {
"CARRIER": {
"value": "UPS"
},
"SHIPPED_WITH_ACCOUNT_DESCRIPTION": {
"value": "UPS Connect"
},
"SHIPPED_WITH_PROFILE_NAME": {
"value": ""
},
"ON_HOLD": {
"value": "false"
}
},
"notes": [],
"tags": [
"print"
],
"relations": [],
"source": {
"name": "Your Application",
"account": "Your Customer",
"channel": null,
"retrieved_at": "2025-02-24T23:13:55.891907Z",
"updated_at": "2025-02-24T23:13:55.956006Z",
"id": null
},
"billing": {
"status": "paid",
"subtotal": "200.00 USD",
"shipping": null,
"tax": null,
"total": null,
"bill_to": null
},
"shipping": {
"status": "fulfilled",
"to_ship_at": "2025-02-24T23:42:16Z",
"shipped_at": "2025-02-24T23:42:24Z",
"ship_agent": "ReadyShipper 10.4.9b",
"ship_via": "UPS Connect",
"ship_type": "UPS Ground",
"ship_cost": "12.82 USD",
"warehouse": null,
"ship_to": {
"company": "",
"first_name": "Victor",
"last_name": "Ward",
"address_1": "124 RIVINGTON ST",
"address_2": "",
"city": "NEW YORK",
"region": "NY",
"post_code": "10002",
"country": "United States",
"phone": "(222) 222-2222",
"email": "victor@yourcompany.com",
"residential": null,
"validated": false,
"updated_at": "2025-02-24T23:13:55.888593Z",
"created_at": "2025-02-24T23:13:55.866865Z"
},
"ship_from": {
"company": "Shipping Dept.",
"first_name": "Shipping",
"last_name": "Dept.",
"address_1": "6501 E Greenway Pkwy",
"address_2": "",
"city": "Scottsdale",
"region": "AZ",
"post_code": "85254",
"country": "United States",
"phone": "877-818-7447",
"email": "support@readycloud.com",
"residential": true,
"validated": false,
"updated_at": "2025-02-24T23:42:31.049361Z",
"created_at": "2025-02-24T23:13:55.875831Z"
}
}
}

Where to Locate Key Shipping Information:

Field

Location in Response

Shipping Status

shipping.status

Shipping Date

shipping.shipped_at

Shipping Method

shipping.ship_type

Ship Cost

shipping.ship_cost

Notes:

  • The webhook URL (url) must be publicly accessible.

  • Secure your webhook with the auth header in the webhook headers.

  • When an order is fulfilled, the webhook provides fulfillment details such as status, shipped_at, ship_type, ship_cost, but additional polling may be required for tracking numbers and label image data.










3. Retrieve a Single Order for Tracking and Shipping Label

After receiving a webhook for an order where shipping.status=fulfilled, send a GET request to retrieve the tracking number and shipping label data by utilizing the ?expand=boxes parameter in the request URL. If item level data is also required, add the value items to the expand parameter (ex: ?expand=boxes,items). There are two methods to fetch a specific order.

API Endpoint:

1. Include the {order_pk} in the endpoint URL:

πŸ“Œ GET /orgs/{org_pk}/orders/{order_pk}

2. Utilize the orders endpoint with ?primary_id={primary_id} as a search parameter. This method assumes there are no duplicate order numbers in the system, otherwise multiple results will be returned. You may combine multiple search parameters.

πŸ“Œ GET /orgs/{org_pk}/orders/

Note: It is also possible for an order to contain multiple box which would result in multiple tracking numbers and multiple shipping labels. In this case the app should iterate through each object in the boxes array.

The example request below illustrates using the {order_pk} in the endpoint URL as it is more reliable. The expected response also illustrates multiple boxes.
πŸ”—  API Documentation

Example Request:

GET https://www.readycloud.com/api/v2/orgs/{org_pk}/orders/{order_pk}/?expand=boxes
Content-Type: application/json
Authorization: Bearer {YOUR_API_KEY}

Expected Response:

{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/",
"primary_id": "1234",
"unique_id": "00003YxFS2I0L4.aI_YBq4Cp",
"order_number": 1234,
"customer_number": "123",
"po_number": null,
"message": null,
"terms": null,
"ordered_at": "2025-02-21T18:12:34Z",
"printed_at": "2025-02-25T22:32:28Z",
"updated_at": "2025-02-25T22:32:34.394194Z",
"created_at": "2025-02-25T18:22:22.313536Z",
"nested_updated_at": "2025-02-25T22:32:34.458565Z",
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/",
"package_type": "Package",
"length": null,
"width": null,
"height": null,
"weight": "453.5920 g",
"ship_cost": null,
"shipper_release": null,
"insured_value": null,
"insurance_type": null,
"declared_value": "100.00 USD",
"tracking_number": "1ZW226G30311111672",
"confirmation_type": null,
"description": "Keyboard",
"cod": null,
"cod_value": null,
"saturday_delivery": null,
"delivered_at": null,
"updated_at": "2025-02-25T22:32:34.415766Z",
"created_at": "2025-02-25T18:22:22.342220Z",
"packaging": null,
"items": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
],
"custom_fields": {
...
"CONNECTSHIP_LABEL": {
"value": "{label_image_png}",
"type": "image/png",
"encoding": "base64"
},
...
},
"shipping_docs": [],
"tracking": []
},
{
"url": "/api/v2/orgs/fZT/orders/Cq06J/boxes/{box_pk}/",
"package_type": "Package",
"length": null,
"width": null,
"height": null,
"weight": "453.5920 g",
"ship_cost": null,
"shipper_release": false,
"insured_value": null,
"insurance_type": null,
"declared_value": "100.00 USD",
"tracking_number": "1ZW226G30311111681",
"confirmation_type": null,
"description": "Laptop",
"cod": null,
"cod_value": null,
"saturday_delivery": null,
"delivered_at": null,
"updated_at": "2025-02-25T22:32:34.438361Z",
"created_at": "2025-02-25T22:32:22.081869Z",
"packaging": null,
"items": [
{
"url": "/api/v2/orgs/fZT/orders/Cq06J/boxes/{box_pk}/items/{item_pk}/"
}
],
"custom_fields": {
...
"CONNECTSHIP_LABEL": {
"value": "{label_image_png}",
"type": "image/png",
"encoding": "base64"
},
...
},
"shipping_docs": [],
"tracking": []
}
],
"custom_fields": {
"_FR_SUBTOTAL": {
"value": "1"
},
"_FR_REFERENCE_1_FLG": {
"value": "1"
},
"_FR_CARRIER": {
"value": "1"
},
"SO_REFERENCE_2": {
"value": "1234"
},
"SO_REFERENCE_1": {
"value": "Keyboard, Laptop"
},
...
},
"notes": [],
"tags": [
"print"
],
"relations": [],
"source": {
"name": "Your Application",
"account": "Your Customer",
"channel": null,
"retrieved_at": "2025-02-25T18:22:22.326548Z",
"updated_at": "2025-02-25T18:22:22.391382Z",
"id": null
},
"billing": {
"status": "paid",
"subtotal": "200.00 USD",
"shipping": null,
"tax": null,
"total": null,
"bill_to": null
},
"shipping": {
"status": "fulfilled",
"to_ship_at": "2025-02-25T22:32:23Z",
"shipped_at": "2025-02-25T22:32:28Z",
"ship_agent": "ReadyShipper 10.4.9b",
"ship_via": "UPS Connect",
"ship_type": "UPS Ground",
"ship_cost": null,
"warehouse": null,
"ship_to": {
"company": "",
"first_name": "Victor",
"last_name": "Ward",
"address_1": "124 RIVINGTON ST",
"address_2": "",
"city": "NEW YORK",
"region": "NY",
"post_code": "10002",
"country": "United States",
"phone": "(222) 222-2222",
"email": "victor@yourcompany.com",
"residential": null,
"validated": false,
"updated_at": "2025-02-25T18:22:22.321629Z",
"created_at": "2025-02-25T18:22:22.295642Z"
},
"ship_from": {
"company": "Shipping Dept.",
"first_name": "Shipping",
"last_name": "Dept.",
"address_1": "6501 E Greenway Pkwy",
"address_2": "",
"city": "Scottsdale",
"region": "AZ",
"post_code": "85254",
"country": "United States",
"phone": "877-818-7447",
"email": "support@readycloud.com",
"residential": true,
"validated": false,
"updated_at": "2025-02-25T22:32:34.384543Z",
"created_at": "2025-02-25T18:22:22.309740Z"
}
}
}

Where to Locate Key Shipping Information:

Field

Location in Response

Tracking Number

boxes[x].tracking_number

Label Image PNG

boxes[x].custom_fields.CONNECTSHIP_LABEL.value

Notes:

  • If webhook delivery fails, polling ensures you still get shipping details.

  • Poll at reasonable intervals (e.g., every 5-10 minutes) to avoid API rate limits.

  • Store retrieved tracking details in your system for customer notifications.

 

 

 


4. Polling Multiple Orders for Tracking and Shipping Labels

In some applications, especially with a higher volume, it may be more efficient to poll multiple orders at once. For example all orders that have shipped on a certain day. In this case, the API will return a paginated response with up to 70 orders at a time.

Additional search parameters can be used to filter the results. For example, the following parameters will return only orders that have shipped on 2025-02-24 and will expand all of the box objects:

?shippping_status__in=!unfulfilled&shipped_at__gte=2025-02-24&shipped_at__lte=2025-02-25&expand=boxes

API Endpoint:

πŸ“Œ GET /orgs/{org_pk}/orders/

πŸ”—  API Documentation

Example Request:

GET https://www.readycloud.com/api/v2/orgs/{org_pk}/orders/?shippping_status__in=!unfulfilled&shipped_at__gte=2025-02-24&shipped_at__lte=2025-02-25&expand=boxes
Content-Type: application/json
Authorization: Bearer {YOUR_API_KEY}

Expected Response:

{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/",
...
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/",
...
"items": [
{
"url": "/api/v2/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
],
...
"shipping_docs": []
...
}
],
...
"billing": {
...
},
"shipping": {
...
}
},
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}",
...
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/",
...
"items": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
],
...
"shipping_docs": []
...
}
],
...
"billing": {
...
},
"shipping": {
...
}
}
]
}

Notes on Best Practices:

Depending on your application, you may choose which option better suits your needs, or even implement both. If you need a fast response cycle, webhooks are better. They can be trusted most of the time, and for interactive applications can be the best solution, especially paired with a manual "update order" action with which the user can trigger a GET when they expect to see an order shipped but can't see it (which is rare).

If your application is fully automated and unsupervised, polling is usually preferable, keeping an internal timer/counter should be easy unless you deploy on cloud lambda or similar products where it becomes tricky.

Finally, a combination of both approaches gives you the best of both worlds, very fast response time and 100% data integrity. However, that is going to require more time to develop and test. For our own public applications (we use the same public API for our own apps) we picked the complete approach. We implemented it in two steps, starting with webhooks only (handling manually the occasional miss) and then the polling. If you are going to implement both, that's a good plan. For most cases implementing only one feature will be enough and save on development time.


Addendum: Optimizations for API Failures & API Rate Limits

To ensure your integration is resilient and efficient, here are optimizations for handling API failures and API rate limits when working with ReadyCloud.


1. API Rate Limits

  • The ReadyCloud API limits requests to:

    • 60 GET requests per minute

    • 30 POST requests per minute

  • If your application exceeds these limits, ReadyCloud rejects additional requests with a 429 Too Many Requests response.

2. Why You Need to Handle 429 Errors

  • If your application keeps sending requests after hitting the limit, they will not be processed (wasted requests).

  • To avoid unnecessary failures, your system should detect the 429 response and pause before retrying.

3. Exponential Backoff – The Best Throttling Strategy

Instead of retrying immediately or using a fixed delay (which is inefficient), exponential backoff dynamically adjusts wait times based on system behavior.

βœ… How It Works:

  • On each failure, increase the wait time before retrying.

  • If failures continue, keep increasing the delay (exponentially).

  • If a request succeeds, reset the delay and continue as normal.

  • This automatically adapts if ReadyCloud changes its throttling rules or if multiple processes are running.

βœ… Example of Exponential Backoff:
If your request gets a 429 error, you retry with increasing delays:

Retry Attempt

Delay Before Retry

1st Failure

1 second

2nd Failure

2 seconds

3rd Failure

4 seconds

4th Failure

8 seconds

5th Failure

16 seconds

(max delay)

60 seconds

ReadyCloud API Integration Workflow

Overview

This document outlines the workflow for integrating with ReadyCloud’s API, including:

  1. Sending order data to ReadyCloud

  2. Configuring a webhook for order fulfillment notifications

  3. Retrieving a single order to capture tracking and shipping details

  4. Polling multiple orders to capture tracking and shipping details

Each section includes API request examples, expected responses, and best practices.

Your ReadyCloud API key and Org ID can be obtained by following the steps here:

https://kb.readycloud.com/creating-and-refreshing-an-api-token-in-readycloud-

Variables referenced throughout documentation:

Variable

Description

{YOUR_API_KEY}

ReadyCloud API Key

{org_pk}

Org ID

{order_pk}

Order ID

{box_pk}

Box ID

{item_pk}

Item ID

{item_pk}

Webhook ID

{primary_id}

Order Number

{label_image_png}

A base-64 encoded image of the label PNG

{token}

The value passed in the webhook β€œauth” header


















1. Send Order Data to ReadyCloud

To create an order in ReadyCloud, send a POST request to the /orders endpoint.

API Endpoint:

πŸ“Œ POST /orgs/{org_pk}/orders/
πŸ”—  API Documentation

Example Request:

POST https://www.readycloud.com/api/v2/orgs/{org_pk}/orders/
Content-Type: application/json
Authorization: Bearer {YOUR_API_KEY}

{
"primary_id": "1234",
"order_number": 1234,
"customer_number": "123",
"ordered_at": "2025-02-21T18:12:34Z",
"boxes": [
{
"items": [
{
"part_number": "ABC123",
"description": "Laptop",
"quantity": 1,
"unit_price": "100.00 USD",
"unit_weight": "1 lbs",
"image_link": "https://picsum.photos/id/9/512"
},
{
"part_number": "DEF456",
"description": "Keyboard",
"quantity": 1,
"unit_price": "100.00 USD",
"unit_weight": "1 lbs",
"image_link": "https://picsum.photos/id/9/512"
}
]
}
],
"custom_fields": {},
"notes": [],
"tags": [],
"source": {
"name": "Your Application",
"account": "Your Customer"
},
"shipping": {
"status": "unfulfilled",
"ship_via": "UPS Connect",
"ship_type": "UPS Ground",
"ship_to": {
"company": "",
"first_name": "Victor",
"last_name": "Ward",
"address_1": "124 RIVINGTON ST",
"address_2": "",
"city": "NEW YORK",
"region": "NY",
"post_code": "10002",
"country": "United States",
"phone": "(222) 222-2222",
"email": "victor@yourcompany.com"
},
"ship_from": {
"company": "Your Company",
"first_name": "Shipping",
"last_name": "Dept.",
"address_1": "6501 E GREENWAY PKWY",
"address_2": "",
"city": "SCOTTSDALE",
"region": "AZ",
"post_code": "85254",
"country": "United States",
"phone": "(222) 222-2222",
"email": "sales@yourcompany.com"
}
},
"billing": {
"status": "paid"
}
}

Expected Response:

{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/",
"primary_id": "1234",
"unique_id": "00003YwfHE5sdZPU9bKtT38h",
"order_number": 1234,
"customer_number": "123",
"po_number": null,
"message": null,
"terms": null,
"ordered_at": "2025-02-21T18:12:34Z",
"printed_at": null,
"updated_at": "2025-02-24T23:13:55.882339Z",
"created_at": "2025-02-24T23:13:55.881362Z",
"nested_updated_at": "2025-02-24T23:13:55.936263Z",
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}",
"items": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/box_pk}/items/{item_pk}/"
},
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
]
}
],
"custom_fields": {},
"notes": [],
"tags": [],
"relations": [],
"source": {
"name": "Your Application",
"account": "Your Customer",
"channel": null,
"retrieved_at": "2025-02-24T23:13:55.891907Z",
"updated_at": "2025-02-24T23:13:55.956006Z",
"id": null
},
"billing": {
"status": "paid",
"subtotal": null,
"shipping": null,
"tax": null,
"total": null,
"bill_to": null
},
"shipping": {
"status": "unfulfilled",
"to_ship_at": null,
"shipped_at": null,
"ship_agent": null,
"ship_via": "UPS Connect",
"ship_type": "UPS Ground",
"ship_cost": null,
"warehouse": null,
"ship_to": {
"company": "",
"first_name": "Victor",
"last_name": "Ward",
"address_1": "124 RIVINGTON ST",
"address_2": "",
"city": "NEW YORK",
"region": "NY",
"post_code": "10002",
"country": "United States",
"phone": "(222) 222-2222",
"email": "victor@yourcompany.com",
"residential": null,
"validated": false,
"updated_at": "2025-02-24T23:13:55.866898Z",
"created_at": "2025-02-24T23:13:55.866865Z"
},
"ship_from": {
"company": "Your Company",
"first_name": "Shipping",
"last_name": "Dept.",
"address_1": "6501 E GREENWAY PKWY",
"address_2": "",
"city": "SCOTTSDALE",
"region": "AZ",
"post_code": "85254",
"country": "United States",
"phone": "(222) 222-2222",
"email": "sales@yourcompany.com",
"residential": null,
"validated": false,
"updated_at": "2025-02-24T23:13:55.875870Z",
"created_at": "2025-02-24T23:13:55.875831Z"
}
}
}

Notes:

  • The primary_id should be unique.

  • The url should be stored for tracking updates from webhooks and for future polling.

Expected Result in ReadyCloud Dashboard:

You should now be able to view the order in ReadyCloud by navigating the below URL. Make sure you have already logged into ReadyCloud and then replace the {order_pk} in the below URL with the {order_pk} returned in the above API response.

https://www.readycloud.com/orders/{order_pk}

 

 
















2. Configure a Webhook for Order Fulfillment Notifications

To receive real-time notifications when an order’s shipping status changes to fulfilled, configure a webhook for the orders entity.

API Endpoint:

πŸ“Œ POST /orgs/{org_pk}/webhooks/
πŸ”—  API Documentation

Example Request:

POST https:/www.readycloud.com/api/v2/orgs/{org_pk}/webhooks/
Content-Type: application/json
Authorization: Bearer {YOUR_API_KEY}

{
"entity": "orders",
"remote_url": "https://example.com/orders/"
}

Expected Response:

{
"url": "/api/v2/orgs/{org_pk}/webhooks/{webhook_pk}/",
"remote_url": "https://example.com/orders/",
"token": "8uw7pz6qvajizvphb9p5kuf3lq1o8j",
"created_at": "2025-02-24T23:20:17.752336Z",
"updated_at": "2025-02-24T23:20:17.752357Z",
"entity": "orders",
"suspended_at": null
}

Webhook Payload Example (Verify that β€œshipping.status”: β€œfulfilled”):

PUT https://example.com/orders/{order_pk}
auth: {token}

{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/",
"primary_id": "1234",
"unique_id": "00003YwfHE5sdZPU9bKtT38h",
"order_number": 1234,
"customer_number": "123",
"po_number": null,
"message": null,
"terms": null,
"ordered_at": "2025-02-21T18:12:34Z",
"printed_at": "2025-02-24T23:42:24Z",
"updated_at": "2025-02-24T23:42:31.056522Z",
"created_at": "2025-02-24T23:13:55.881362Z",
"nested_updated_at": "2025-02-24T23:42:31.081264Z",
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}",
"items": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/box_pk}/items/{item_pk}/"
},
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
]
}
],
"custom_fields": {
"CARRIER": {
"value": "UPS"
},
"SHIPPED_WITH_ACCOUNT_DESCRIPTION": {
"value": "UPS Connect"
},
"SHIPPED_WITH_PROFILE_NAME": {
"value": ""
},
"ON_HOLD": {
"value": "false"
}
},
"notes": [],
"tags": [
"print"
],
"relations": [],
"source": {
"name": "Your Application",
"account": "Your Customer",
"channel": null,
"retrieved_at": "2025-02-24T23:13:55.891907Z",
"updated_at": "2025-02-24T23:13:55.956006Z",
"id": null
},
"billing": {
"status": "paid",
"subtotal": "200.00 USD",
"shipping": null,
"tax": null,
"total": null,
"bill_to": null
},
"shipping": {
"status": "fulfilled",
"to_ship_at": "2025-02-24T23:42:16Z",
"shipped_at": "2025-02-24T23:42:24Z",
"ship_agent": "ReadyShipper 10.4.9b",
"ship_via": "UPS Connect",
"ship_type": "UPS Ground",
"ship_cost": "12.82 USD",
"warehouse": null,
"ship_to": {
"company": "",
"first_name": "Victor",
"last_name": "Ward",
"address_1": "124 RIVINGTON ST",
"address_2": "",
"city": "NEW YORK",
"region": "NY",
"post_code": "10002",
"country": "United States",
"phone": "(222) 222-2222",
"email": "victor@yourcompany.com",
"residential": null,
"validated": false,
"updated_at": "2025-02-24T23:13:55.888593Z",
"created_at": "2025-02-24T23:13:55.866865Z"
},
"ship_from": {
"company": "Shipping Dept.",
"first_name": "Shipping",
"last_name": "Dept.",
"address_1": "6501 E Greenway Pkwy",
"address_2": "",
"city": "Scottsdale",
"region": "AZ",
"post_code": "85254",
"country": "United States",
"phone": "877-818-7447",
"email": "support@readycloud.com",
"residential": true,
"validated": false,
"updated_at": "2025-02-24T23:42:31.049361Z",
"created_at": "2025-02-24T23:13:55.875831Z"
}
}
}

Where to Locate Key Shipping Information:

Field

Location in Response

Shipping Status

shipping.status

Shipping Date

shipping.shipped_at

Shipping Method

shipping.ship_type

Ship Cost

shipping.ship_cost

Notes:

  • The webhook URL (url) must be publicly accessible.

  • Secure your webhook with the auth header in the webhook headers.

  • When an order is fulfilled, the webhook provides fulfillment details such as status, shipped_at, ship_type, ship_cost, but additional polling may be required for tracking numbers and label image data.










3. Retrieve a Single Order for Tracking and Shipping Label

After receiving a webhook for an order where shipping.status=fulfilled, send a GET request to retrieve the tracking number and shipping label data by utilizing the ?expand=boxes parameter in the request URL. If item level data is also required, add the value items to the expand parameter (ex: ?expand=boxes,items). There are two methods to fetch a specific order.

API Endpoint:

1. Include the {order_pk} in the endpoint URL:

πŸ“Œ GET /orgs/{org_pk}/orders/{order_pk}

2. Utilize the orders endpoint with ?primary_id={primary_id} as a search parameter. This method assumes there are no duplicate order numbers in the system, otherwise multiple results will be returned. You may combine multiple search parameters.

πŸ“Œ GET /orgs/{org_pk}/orders/

Note: It is also possible for an order to contain multiple box which would result in multiple tracking numbers and multiple shipping labels. In this case the app should iterate through each object in the boxes array.

The example request below illustrates using the {order_pk} in the endpoint URL as it is more reliable. The expected response also illustrates multiple boxes.
πŸ”—  API Documentation

Example Request:

GET https://www.readycloud.com/api/v2/orgs/{org_pk}/orders/{order_pk}/?expand=boxes
Content-Type: application/json
Authorization: Bearer {YOUR_API_KEY}

Expected Response:

{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/",
"primary_id": "1234",
"unique_id": "00003YxFS2I0L4.aI_YBq4Cp",
"order_number": 1234,
"customer_number": "123",
"po_number": null,
"message": null,
"terms": null,
"ordered_at": "2025-02-21T18:12:34Z",
"printed_at": "2025-02-25T22:32:28Z",
"updated_at": "2025-02-25T22:32:34.394194Z",
"created_at": "2025-02-25T18:22:22.313536Z",
"nested_updated_at": "2025-02-25T22:32:34.458565Z",
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/",
"package_type": "Package",
"length": null,
"width": null,
"height": null,
"weight": "453.5920 g",
"ship_cost": null,
"shipper_release": null,
"insured_value": null,
"insurance_type": null,
"declared_value": "100.00 USD",
"tracking_number": "1ZW226G30311111672",
"confirmation_type": null,
"description": "Keyboard",
"cod": null,
"cod_value": null,
"saturday_delivery": null,
"delivered_at": null,
"updated_at": "2025-02-25T22:32:34.415766Z",
"created_at": "2025-02-25T18:22:22.342220Z",
"packaging": null,
"items": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
],
"custom_fields": {
...
"CONNECTSHIP_LABEL": {
"value": "{label_image_png}",
"type": "image/png",
"encoding": "base64"
},
...
},
"shipping_docs": [],
"tracking": []
},
{
"url": "/api/v2/orgs/fZT/orders/Cq06J/boxes/{box_pk}/",
"package_type": "Package",
"length": null,
"width": null,
"height": null,
"weight": "453.5920 g",
"ship_cost": null,
"shipper_release": false,
"insured_value": null,
"insurance_type": null,
"declared_value": "100.00 USD",
"tracking_number": "1ZW226G30311111681",
"confirmation_type": null,
"description": "Laptop",
"cod": null,
"cod_value": null,
"saturday_delivery": null,
"delivered_at": null,
"updated_at": "2025-02-25T22:32:34.438361Z",
"created_at": "2025-02-25T22:32:22.081869Z",
"packaging": null,
"items": [
{
"url": "/api/v2/orgs/fZT/orders/Cq06J/boxes/{box_pk}/items/{item_pk}/"
}
],
"custom_fields": {
...
"CONNECTSHIP_LABEL": {
"value": "{label_image_png}",
"type": "image/png",
"encoding": "base64"
},
...
},
"shipping_docs": [],
"tracking": []
}
],
"custom_fields": {
"_FR_SUBTOTAL": {
"value": "1"
},
"_FR_REFERENCE_1_FLG": {
"value": "1"
},
"_FR_CARRIER": {
"value": "1"
},
"SO_REFERENCE_2": {
"value": "1234"
},
"SO_REFERENCE_1": {
"value": "Keyboard, Laptop"
},
...
},
"notes": [],
"tags": [
"print"
],
"relations": [],
"source": {
"name": "Your Application",
"account": "Your Customer",
"channel": null,
"retrieved_at": "2025-02-25T18:22:22.326548Z",
"updated_at": "2025-02-25T18:22:22.391382Z",
"id": null
},
"billing": {
"status": "paid",
"subtotal": "200.00 USD",
"shipping": null,
"tax": null,
"total": null,
"bill_to": null
},
"shipping": {
"status": "fulfilled",
"to_ship_at": "2025-02-25T22:32:23Z",
"shipped_at": "2025-02-25T22:32:28Z",
"ship_agent": "ReadyShipper 10.4.9b",
"ship_via": "UPS Connect",
"ship_type": "UPS Ground",
"ship_cost": null,
"warehouse": null,
"ship_to": {
"company": "",
"first_name": "Victor",
"last_name": "Ward",
"address_1": "124 RIVINGTON ST",
"address_2": "",
"city": "NEW YORK",
"region": "NY",
"post_code": "10002",
"country": "United States",
"phone": "(222) 222-2222",
"email": "victor@yourcompany.com",
"residential": null,
"validated": false,
"updated_at": "2025-02-25T18:22:22.321629Z",
"created_at": "2025-02-25T18:22:22.295642Z"
},
"ship_from": {
"company": "Shipping Dept.",
"first_name": "Shipping",
"last_name": "Dept.",
"address_1": "6501 E Greenway Pkwy",
"address_2": "",
"city": "Scottsdale",
"region": "AZ",
"post_code": "85254",
"country": "United States",
"phone": "877-818-7447",
"email": "support@readycloud.com",
"residential": true,
"validated": false,
"updated_at": "2025-02-25T22:32:34.384543Z",
"created_at": "2025-02-25T18:22:22.309740Z"
}
}
}

Where to Locate Key Shipping Information:

Field

Location in Response

Tracking Number

boxes[x].tracking_number

Label Image PNG

boxes[x].custom_fields.CONNECTSHIP_LABEL.value

Notes:

  • If webhook delivery fails, polling ensures you still get shipping details.

  • Poll at reasonable intervals (e.g., every 5-10 minutes) to avoid API rate limits.

  • Store retrieved tracking details in your system for customer notifications.

 

 

 


4. Polling Multiple Orders for Tracking and Shipping Labels

In some applications, especially with a higher volume, it may be more efficient to poll multiple orders at once. For example all orders that have shipped on a certain day. In this case, the API will return a paginated response with up to 70 orders at a time.

Additional search parameters can be used to filter the results. For example, the following parameters will return only orders that have shipped on 2025-02-24 and will expand all of the box objects:

?shippping_status__in=!unfulfilled&shipped_at__gte=2025-02-24&shipped_at__lte=2025-02-25&expand=boxes

API Endpoint:

πŸ“Œ GET /orgs/{org_pk}/orders/

πŸ”—  API Documentation

Example Request:

GET https://www.readycloud.com/api/v2/orgs/{org_pk}/orders/?shippping_status__in=!unfulfilled&shipped_at__gte=2025-02-24&shipped_at__lte=2025-02-25&expand=boxes
Content-Type: application/json
Authorization: Bearer {YOUR_API_KEY}

Expected Response:

{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/",
...
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/",
...
"items": [
{
"url": "/api/v2/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
],
...
"shipping_docs": []
...
}
],
...
"billing": {
...
},
"shipping": {
...
}
},
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}",
...
"boxes": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/",
...
"items": [
{
"url": "/api/v2/orgs/{org_pk}/orders/{order_pk}/boxes/{box_pk}/items/{item_pk}/"
}
],
...
"shipping_docs": []
...
}
],
...
"billing": {
...
},
"shipping": {
...
}
}
]
}

Notes on Best Practices:

Depending on your application, you may choose which option better suits your needs, or even implement both. If you need a fast response cycle, webhooks are better. They can be trusted most of the time, and for interactive applications can be the best solution, especially paired with a manual "update order" action with which the user can trigger a GET when they expect to see an order shipped but can't see it (which is rare).

If your application is fully automated and unsupervised, polling is usually preferable, keeping an internal timer/counter should be easy unless you deploy on cloud lambda or similar products where it becomes tricky.

Finally, a combination of both approaches gives you the best of both worlds, very fast response time and 100% data integrity. However, that is going to require more time to develop and test. For our own public applications (we use the same public API for our own apps) we picked the complete approach. We implemented it in two steps, starting with webhooks only (handling manually the occasional miss) and then the polling. If you are going to implement both, that's a good plan. For most cases implementing only one feature will be enough and save on development time.


Addendum: Optimizations for API Failures & API Rate Limits

To ensure your integration is resilient and efficient, here are optimizations for handling API failures and API rate limits when working with ReadyCloud.


1. API Rate Limits

  • The ReadyCloud API limits requests to:

    • 60 GET requests per minute

    • 30 POST requests per minute

  • If your application exceeds these limits, ReadyCloud rejects additional requests with a 429 Too Many Requests response.

2. Why You Need to Handle 429 Errors

  • If your application keeps sending requests after hitting the limit, they will not be processed (wasted requests).

  • To avoid unnecessary failures, your system should detect the 429 response and pause before retrying.

3. Exponential Backoff – The Best Throttling Strategy

Instead of retrying immediately or using a fixed delay (which is inefficient), exponential backoff dynamically adjusts wait times based on system behavior.

βœ… How It Works:

  • On each failure, increase the wait time before retrying.

  • If failures continue, keep increasing the delay (exponentially).

  • If a request succeeds, reset the delay and continue as normal.

  • This automatically adapts if ReadyCloud changes its throttling rules or if multiple processes are running.

βœ… Example of Exponential Backoff:
If your request gets a 429 error, you retry with increasing delays:

Retry Attempt

Delay Before Retry

1st Failure

1 second

2nd Failure

2 seconds

3rd Failure

4 seconds

4th Failure

8 seconds

5th Failure

16 seconds

(max delay)

60 seconds