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 Code | Description |
---|---|
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"
}