API

Introduction

shipcloud is a shipping service provider that makes it easy for developers to integrate shipping using one of the major carriers on the German market into their own software, onlineshop or ERP solution. We've basically built a wrapper around the carriers' webservices we support so you won't have to integrate each and every carrier by yourself.

To make it easier for you the developer, we've created the shipcloud API deliberately using the RESTful architectural style. This means if you're familiar with REST and using RESTful services, you will have no problems using our API. As it's common when implementing a REST-API we're using resource-oriented URLs and HTTP authentication.

Authentication

For developers to test their code before shipping it, we're supplying every account with test and live API keys. Every call to our API is secured by an API key. This key is tied specificly to your account and therefore should never be given to anyone else outside of your control. You are able to manage your API keys from your account page.

To use the API key you'll have to send it with every request being made. Authentication to our API has to be done via HTTP Basic Auth. You'll have to provide your API key as the basic auth username. You don't have to provide a password.

Be advised: The API key has to be Base64 encoded.

Aside from sending your API key all API requests must be made using HTTPS. Don't bother trying to use HTTP. It will fail!

SSL certificate

For clients having to install our SSL certificate to create secure connections, you can download it:

Rate Limiting

We are limiting the number of requests a user can send to our API in a given set of time. When the interval ends, the user gets another set of requests. To know the current limits of a user we are returning the following four header fields with every response of our API.

  • RateLimit-Limit, number the shows the overall limit of requests this user can send (e.g. 120)
  • RateLimit-Interval, number of seconds the interval for this user is long (e.g. 60)
  • RateLimit-Remaining, remaining number of request in the current interval (e.g. 111)
  • RateLimit-Reset, number of seconds that shows when the request rate limit resets (e.g. 42)

Parameters

Many API methods take optional parameters. For GET requests, any parameters not specified as a segment in the path can be passed as an HTTP query string parameter:

curl -i -u be51608682014a3adf620fc252d63390: "https://api.shipcloud.io/v1/shipments?service=returns"

For POST, PATCH, PUT, and DELETE requests, parameters not included in the URL should be encoded as JSON with a Content-Type of application/json:

curl -i -u be51608682014a3adf620fc252d63390: -H "Content-Type: application/json" -d '{"service":["returns"]}' "https://api.shipcloud.io/v1/shipments"

Sanitization

To be able to send a clean request to the carriers, we are doing a little sanitization of the data that gets transmitted to the api. Currently whitespace will be trimmed from the edges and control characters will be removed.

Versioning

As with every API we will be releasing new versions from time to time. We do promise to adhere to the following API contract:

  • No value types or fields will be changed or deleted in the same API version
  • What we will change within the same API version:
    • add new fields to an object
    • add new API endpoints
    • required fields can become optional
    • endpoints can become deprecated

In case we introduce breaking changes we will adjust the API base path to reflect each new major version. So consecutive releases will be called using /v2/, /v3/ and so on.

Address handling

When sending to or from parameters you have to specify a contact for the shipment. This can either be a company or a person identified by first_name and last_name. So although the entries are marked as being optional, one of them has to be specified in the request.

Label Format

You can specify the format of the shipping label that you want to get returned by adding label.format to the request. Using this entry you can specify the format / size using one of the predefined strings.

Not all carriers support the same formats for their labels. You can find out which label formats we support on each of the carrier pages.

We currently support the following label formats:

  • pdf_a5
  • pdf_a6
  • pdf_a7
  • pdf_100x70mm
  • pdf_103x199mm
  • zpl2_4x6in_203dpi
  • zpl2_4x6in_300dpi
  • zpl2_100x70mm_203dpi
  • zpl2_103x199mm_203dpi
  • zpl2_4x8in_203dpi

Multi package shipments

We also support sending shipments with multiple packages. Instead of providing a single package object in your request, you need to provide an array of packages. This allows you to send multiple packages with a single shipment.

To use this feature, include an array of package objects in your request, like this:

POST /shipments
{
  "carrier": "ups",
  "service": "standard",
  "create_shipping_label": true,
  "from": {
    "company": "FromCompany",
    "first_name": "FromFirstName",
    "last_name": "FromLastName",
    "street": "St. Annenufer",
    "street_no": "5",
    "city": "Hamburg",
    "zip_code": "20457",
    "country": "DE",
    "phone": "+49405551234"
  },
  "to": {
    "first_name": "ToFirstName",
    "last_name": "ToLastName",
    "street": "Lohhof",
    "street_no": "24",
    "city": "Hamburg",
    "zip_code": "20535",
    "country": "DE",
    "phone": "+49405551234"
  },
  "packages": [
    {
      "length": "30",
      "width": "30",
      "height": "30",
      "weight": "3",
      "type": "parcel",
      "description": "PackageDescription1"
    },
    {
      "length": "20",
      "width": "20",
      "height": "20",
      "weight": "2.0",
      "type": "parcel",
      "description": "PackageDescription2"
    }
  ],
  "reference_number": "Ref-No-17433"
}

Please note, this feature is currently only supported by the carrier UPS, with more carriers to be added soon.

Important:

  • For carriers not supporting multi-package shipments, you will need to send an array with just one package.
  • Creating shipments using the package object is still supported for now, but is deprecated.

Metadata

We've been giving you the possibility to specifiy a reference number when creating a shipment to make it easier for you to find out, which shipcloud shipment belongs to which order in your shop or system. When creating a shipment you are now able to send us additional data, that we store for you. This so called metadata is a structured object and can be any combination of key-value pairs.

POST /shipments
{
  "metadata": {
    "products": {
      "product": {
        "id": 1234567,
        "name": "blue shirt",
        "price": 42.12,
        "currency": "EUR"
      },
      "product": {
        "id": 0987654,
        "name": "yellow shirt",
        "price": 22.99,
        "currency": "EUR"
      }
    },
    "order_number": "123456",
    "order_date": "2015-06-01",
    "user_e_mail": "user@example.com",
    "order_total": {
      "amount": 65.11,
      "currency": "EUR"
    }
  }
}

Timeouts

The services of the carriers we're supporting can be very slow at times. Since we're not queing requests to create shipping labels at a later point in time, please account for slow response times. We'd suggest setting a timeout of a little more than a minute to be absolutely sure that you're not missing our responses.

Sandbox vs. Production

When creating an account at shipcloud you get access for 2 systems. A sandbox and a production system. The first one can be used to tinker with (e.g. for developing the integration of shipcloud into your own platform) while the production system is used for the actual creation of shipping labels.

Keys

Therefore when you create an account at shipcloud, 2 api keys get generated. A sandbox key that you can use for testing our api and a live key, that can be used to create the actual shipping labels you're going to put on the packages you're sending.

If at any time you feel the need to generate a new set of api keys (e.g. because you get the feeling, that your system has been compromised) you can do that in the shipcloud backoffice by clicking your email address at the upper right corner and selecting the menu item API Key.

Shipment prices

When using the sandbox key we will always return 0,0 as price.

Cleanup

We're currently deleting sandbox shipments 2 weeks after they've been created. So it's best practice to create a new shipment first if you want to test updating or deleting it.

Plan up-/downgrades

If you feel like tinkering with our api you can always register for free using our developer plan. If you're satisfied with our service feel free to upgrade to a payed plan. Upgrades from one payed plan to a higher one can be done at any time. We use the balance of your current plan against the first month of your new one, so you won't be billed extra for upgrading before your current plan runs out.

Prices & Vat

All of our prices are displayed in Euro and without VAT. We will however charge you with the full German value added tax which is 19% at the moment.

Pickup Requests

Some carriers require you to provide pickup information for creating a shipment to make the process of planning pickups easier for them. Others want you to send them a (detailed) pickup request at the end of the business day so they can plan pickups for the following work day. See below for a detailed description about what to use when.

While creating shipments

For some carriers if you don't have regular pickups you will have to provide the information when creating a shipment. For this you can add a pickup element to your shipment request. This method is applicable for the following carriers:

For existing shipments

Most of the carriers we provide want you to send them a pickup request with the aggregated shipment numbers at the end of the business day. To achieve this you can create a pickup request and send us either just the name of the carrier and additionally the shipment ids of the shipments you want to have picked up.

Webhooks

If you automatically want to react to events happening within the shipcloud system, webhooks are the right thing for you. All you need to do is provide us with a URL we should call once something happens. You can also specify which events should trigger calling your URL. Maybe you only want to be notified, when a package gets delivered to one of your customers.

When an event is triggered, we'll send an HTTP POST request to your URL, containing a JSON payload, with all the information necessary. Here's our sample payload you get when testing a webhook through our website:

{
  "id": "ef9df623-6974-4a4b-9a99-c0ec5b58b136",
  "webhook_id": "77ba9db5-2207-4b21-be06-dff0ba7f6989",
  "occured_at": "2015-02-17T14:20:42+01:00",
  "type": "example.event",
  "data": {
    "id": "es40a6e7a83ea8253f54eb414606626172b523d8",
    "url": "/v1/shipments/es40a6e7a83ea8253f54eb414606626172b523d8",
    "object_type": "shipment"
  }
}

Notice: Our payload only contains the data that was mentioned above. This means that after a webhook was fired, you will have to call our api to get detailed information about the shipment. This way only someone with the correct api key is able to access your customers data.

Event types

You can currently subscribe to the following event types:

Type Description
shipment.status.deleted A label has been deleted
shipment.tracking.label_created A label has been created
shipment.tracking.picked_up Shipment was picked up by carrier
shipment.tracking.transit Shipment is in transit
shipment.tracking.out_for_delivery Out for delivery
shipment.tracking.delivered Delivered
shipment.tracking.awaits_pickup_by_receiver Awaiting pickup by the receiver
shipment.tracking.canceled label has been deleted
shipment.tracking.delayed Delivery will be delayed
shipment.tracking.exception There's a problem with the shipment
shipment.tracking.not_delivered Not delivered
shipment.tracking.destroyed Destroyed by customs or other higher authorities.
shipment.tracking.notification Carrier internal notification. Tracking events within the shipment will carry more elaborate information.
shipment.tracking.unknown Status unknown

Event type shipment delete

When subscribing to this event type, you will get notified when a shipment has been deleted at shipcloud.

Notice: For the shipment.status.deleted event type, the payload differs a little bit to the example mentioned above. Since the shipment doesn't exist anymore, we do not return a URL to the ressource.

{
  "id":"b826b716-9da9-4960-992b-7999574886a4",
  "occured_at":"2020-05-28T06:44:26+02:00",
  "type":"shipment.status.deleted",
  "data":{
    "id":"0ba10fb9af418e9c159a5449219f722e99fba788",
    "object_type":"shipment"
  },
  "webhook_id":"27f54ad2-f166-42b2-9de5-76acb3cf107b"
}

Catch all webhooks

If you don't want to subscribe to a specific event or you want to be notified by all events we're firing using one of our catch all options is the best way to go. Defining a catch all webhook is easy. Simply use an asterisk instead of a specific status as the last element in the notation.

We're supporting all places in the notation hierarchy as long as the asterisk is the last element defined.

Notice: By using catch all webhooks you are going the first step in getting notified about all current and future events we're supporting.

Examples for catch all webhooks

All events for tracking shipments
{
  "url": "https://example.com/webhook",
  "event_types": ["shipment.tracking.*"]
}
All events for shipments
{
  "url": "https://example.com/webhook",
  "event_types": ["shipment.*"]
}
All events
{
  "url": "https://example.com/webhook",
  "event_types": ["*"]
}

Configuration

To configure webhooks just click on Configurations in the shipcloud backoffice to reveal a webhook nav entry. There you can add webhooks and specify which events should trigger sending a message to your URL.

Security

You can secure the endpoint(s) on your system(s) by using basic authorization. When creating a webhook you provide us a username and (optionally a) password.

{
  "url": "https://example.com/webhook",
  "event_types": ["shipment.*"],
  "security": {
    "type": "basic_auth",
    "username": "shipcloud_webhook_username",
    "password": "Very$ecurePassw0rd"
  }
}

Testing

There are a lot of tools out there for testing webhooks. If you'd like a starting point check out this blogpost called 60+ Tools and Services for API and Webhook Logging, Debugging, Testing, Monitoring, Documentation and Discovery). We'd recommend using a service like requestbin.com to have reliable responses for your tests. This way you don't have to create shipments just for testing handling shipments afterwards.

Developer accounts

If you're usind TDD (test driven development) another thing we'd recommend is creating a second account at shipcloud for all your testing needs. This way you can separate further development on your platform from your live processes.

Automatic deactivation

If the URL you provided when configuring the webhook can't be reached (a http status code of 4xx or 5xx is returned), we'll try to contact it a few minutes later. After 15 failed attempts to send you the data, we're giving up and the webhook will be deactivated automatically.

At the same time we will send an email to the address that was provided for the account, notifying you of this fact. You should reactivate the webhook in the shipcloud WebUI once your system is up and reachable again.

Checkout / Routing Rules

Introduction

Shipcloud is offering a set of APIs that can support and improve the checkout experience of your customers.

  • Routing Rules can be used to retrieve and present a list of available carrier + service combinations (based on the address and cart data) during the checkout.
  • The pickup & dropoff point API provides a list of pickup and dropoff locations for a specific carrier. That list can be rendered in a checkout (for example Google maps based) to help the customer to identify close by locations to pick up their parcel.
  • The shipment quote API provides your shipcloud rates for a given route. This can be used to determine if shipping should be charged during a checkout. If so, the quote response can be used as a basis to calculate the final charges that the end customer should be charged with.

Routing rules

Routing Rules allow you to define custom shipping rules using various methods organized in a structured tree format. These rules determine which carrier-service combinations are available for the requested shipping details. Shipping details can include: Ship to address, ship from address, direction, package data.

There are two ways to make use of routing rules:

  1. Call the routing rules API to allocate a carrier service combination to an order and create a shipping label based on that right away.
  2. Call the routing rules API during a checkout session to present available carriers and delivery options (e.g. Express, Express early,…). This could also be used to show estiamted delivery timeframes and shipping costs

Additional Ressources

For further assistance, check out our Help Center article on Routing Rules integration.