API Reference

On this page you'll find information regarding errors that you might encounter when using the Kosmo API. Hopefully they are self explanatory so we can help solve them.

Dealing with errors is annoying. That's why we've worked on this page to explain the kind of errors you can face and how to solve them.

Response Codes

We use the following HTTP status code in the response depending on the success or failure:

Status CodeDescription
200✅ Success - The content is available in the response body.
201✅ Success - The content was created successfully on Kosmo.
204✅ Success - No content to return.
400❌ Bad Request Error - Request returned an error, detail in content.
401❌ Unauthorized - The Kosmo credentials provided are not valid.
404❌ Not Found - The resource you try to access cannot be found.
409❌ Conflict - The action you do conflicts with another pending action.
500❌ Internal Server Error - The detail of the error is available in the response body.

Kosmo API errors are returned in JSON format. For example, an error might look like this:

{
	"details": [
		{
		"field": "CreateQuotesRequest.Pickup.Sender.Phone",
		"key": "missing_required_field",
		"message": "missing required field: Phone"
		}
	],
	"key": "invalid_request_error"
}

Typically, an error response will have the following parameters:

  • key: a unique key for the error. Check the table below to see how to handle each error key.
  • message: human-readable description of the error.
  • filed: The specific field in the request body that has an issue.

General error handling notes

Here is our recommendation in terms of retrying on errors:

50x errors

Implement an automated exponential backoff of up to five retries. We recommend that you use a base interval of three seconds with a factor of two. For example, the first retry should be after three seconds, the second retry should be after 6 seconds (2_3), the third retry should be after 12 seconds (2_6), the fourth retry should be after 24 seconds (2_12), and the fifth retry is after 48 seconds (2_24).

40x errors

You should not retry making requests if you get 40x response as this is a client error.

400 missing_required_field

Request body is missing a required field.

{
    "details": [
        {
            "field": "CreateQuotesRequest.Dropoffs[0].Receiver.Fullname",
            "key": "missing_required_field",
            "message": "missing required field: Fullname"
        }
    ],
    "key": "invalid_request_error"
}

Reason
You sent a request without a required field. For example:

{
  "dropoffs": [
          {
              "location": {
                  "address": "60 Jln Penjara, Singapore",
                  "postalCode": "149375",
                  "country": "SG",
                  "lat": 1.3209804750650018,
                  "lng": 104.89702883067434,
                  "addressDetails": "",
                  "instructions": ""
              },
              "receiver": {
                  "fullname": "",
                  "phone": "+6512345678"
              },
       }
  ]
}

Solution

Check the error message to see which field you need to provide. If you're unsure what information to provide or the format, check our API reference documentation.

400 max_count_of_dropoff

Сount of dropoff cannot be greater than 20.

{
  "key":"invalid_request_error",
  "details":[
    {
      "key":"max_count_of_dropoff",
      "message":"count of dropoffs greater 20",
      "field":"CreateQuotesRequest.dropoffs"
    }
  ]
}

Reason
You sent a request with a dropoff count greater than 20.

Solution
Check the dropoff count and separate into multiple orders. An order has a max dropoff count of 20.

400 pickup_start_time_too_soon

Pickup time must be greater than now.

{
  "key":"invalid_request_error",
  "details":[
    {
      "key":"pickup_start_time_too_soon",
      "message":"pickupStartTime must be empty or after now",
      "field":"CreateQuotesRequest.pickupStartTime"
    }
  ]
}

Reason
You sent a request with a pickup start time less than now.

{
    "deliveryType": "ASAP",
    "pickupStartTime": "2022-11-11T10:15:00.000000Z",
     ...
}

Solution
Check the pickup start time and set the time after now.

400 pickup_start_time_too_late

Pickup time must be later than now.

{
  "key":"invalid_request_error",
  "details":[
    {
      "key":"pickup_start_time_too_late",
      "message":"pickupStartTime must be empty or at most 14 days from now",
      "field":"CreateQuotesRequest.pickupStartTime"
    }
  ]
}

Reason
You sent a request with a pickup start time further than 14 days from now.

{
    "deliveryType": "ASAP",
    "pickupStartTime": "2025-11-11T10:15:00.000000Z",
     ...
}

Solution
Check the pickup start time and set the time at 14 days from now at max.

400 cancellation_invalid_state

Cancellation is only allowed when the status is before TO_PICKUP status

{
    "key": "cancellation_invalid_state",
    "message": "delivery is already assigned to a rider: Delivery status not allowed for cancel"
}

Reason
You sent a request to cancel an order, but the order status is after TO_PICKUP. You can only cancel orders with the status before TO_PICKUP.

400 request_body_is_required

{
    "key": "request_body_is_required",
    "message": "Request body is required"
}

Reason
You sent an empty request body

Solution
Check your request body

404 not_found_error

Your requested resource was not found. This could be caused by either calling a wrong URL, or by looking up a delivery that doesn't exist

{
    "key": "not_found_error",
    "message": "delivery not found: No delivery was found with given ID"
}

400 quote_expired

This quote is expired.

{
    "key": "quote_expired",
    "message": "Quote expired"
}

400 quote_already_used

This quote is already used for another order.

{
    "details": [
        {
            "key": "order_id",
            "message": "SG-18LwUYHMyYs"
        }
    ],
    "key": "quote_already_used",
    "message": "Quote already used for order SG-18LwUYHMyYs"
}

400 org_has_no_active_payment_method

Organization doesn't have an active payment method in Stripe.

{
    "key": "org_has_no_active_payment_method",
    "message": "Organization has no active payment method"
}

Reason
Your organization doesn't have an active payment method in Stripe

Solution
Add payment method in Stripe

400

{
    "key": "unable_find_address",
    "message": "Unable to find address"
}

Reason
We cannot find coordinates by address or address by coordinates.

Solution
You can provide a more accurate address or send an address with the coordinates

409 request_is_changed

You use the idempotency key, but the request data has been changed in the subsequent request.

{
    "key": "request_is_changed",
    "message": "Request is changed, please try again with new idempotency key"
}

409 conflict_error

Your request fails because there is another request in progress. If you use the idempotency key you can try to retry the request after a few seconds. If you don't use the idempotency request - recommended not to retry it because it can potentially create a double order. We have protection for the same quote to be used only once, but it's not safe to rely on it.

{
    "key": "conflict_error",
    "message": "Request is in progress"
}