REST API Errors
UltraCart REST API Errors - Developer's Reference Guide
Table of Contents
Overview
The UltraCart REST API uses standard HTTP status codes and returns structured error messages to help developers diagnose and resolve issues. This guide covers both the legacy REST API (Version 1) and the current REST API (Version 2).
API Base URLs:
Version 2:
https://secure.ultracart.com/rest/v2Version 1 (Legacy):
https://secure.ultracart.com/rest
Important Note: Version 1 is legacy and maintained only for backward compatibility. All new development should use Version 2 with the official SDKs.
Error Response Structure
Version 2 Error Format
All API responses in Version 2 include an error object when errors occur:
{
"error": {
"developer_message": "Detailed technical error message for developers",
"user_message": "User-friendly error message suitable for display"
},
"metadata": {}
}
Key Fields:
developer_message: Technical details for debugging (log this for troubleshooting)user_message: Customer-facing message (safe to display to end users)metadata: Additional context about the error (optional)
Example Error Handling (Multiple Languages)
PHP:
$api_response = $order_api->getOrder($order_id, $expansion);
if ($api_response->getError() != null) {
error_log($api_response->getError()->getDeveloperMessage());
error_log($api_response->getError()->getUserMessage());
exit();
}
Python:
api_response = order_api.get_order(order_id, expand=expand)
if api_response.error:
print(f"Developer Message: {api_response.error.developer_message}")
print(f"User Message: {api_response.error.user_message}")
exit()
JavaScript/TypeScript:
const apiResponse = await orderApi.getOrder({orderId, expand: expansion});
if (apiResponse.error) {
console.error('Developer Message:', apiResponse.error.developer_message);
console.error('User Message:', apiResponse.error.user_message);
throw new Error('Failed to retrieve order');
}
C#:
OrderResponse apiResponse = orderApi.GetOrder(orderId, expansion);
if (apiResponse.Error != null) {
Console.Error.WriteLine(apiResponse.Error.DeveloperMessage);
Console.Error.WriteLine(apiResponse.Error.UserMessage);
Environment.Exit(1);
}
Ruby:
api_response = order_api.get_orders_batch(
order_query_batch: order_batch,
opts: { '_expand' => expansion }
)
if api_response.error
warn "Developer Message: #{api_response.error.developer_message}"
warn "User Message: #{api_response.error.user_message}"
exit 1
end
Version 1 Error Format
Version 1 returns errors as an array in the errors field:
{
"errors": [
"Error message 1",
"Error message 2"
]
}
Validation Errors:
{
"validationErrors": [
{
"field": "email",
"message": "Email address is required"
}
]
}
HTTP Status Codes
2xx Success Codes
Code | Status | Description |
|---|---|---|
200 | OK | Request succeeded, response contains data |
201 | Created | Resource created successfully |
204 | No Content | Request succeeded, no content in response (e.g., delete operations) |
4xx Client Error Codes
Code | Status | Description | Common Causes |
|---|---|---|---|
400 | Bad Request | Malformed request syntax or invalid parameters | Invalid JSON, missing required fields, incorrect data types |
401 | Unauthorized | Authentication required or failed | Missing/invalid API key, expired OAuth token, insufficient permissions |
403 | Forbidden | Valid request but server refuses to respond | Permission denied, API access not enabled for user, IP restriction |
404 | Not Found | Resource does not exist | Invalid order ID, item ID, or endpoint URL; typos in URL |
405 | Method Not Allowed | HTTP method not supported for endpoint | Using GET instead of POST, or vice versa |
422 | Unprocessable Entity | Request well-formed but contains semantic errors | Invalid field values, failed business logic validation |
429 | Too Many Requests | Rate limit exceeded | Making too many requests in a short time period |
5xx Server Error Codes
Code | Status | Description | Action |
|---|---|---|---|
500 | Internal Server Error | Unexpected server-side error | Retry with exponential backoff, contact support if persists |
502 | Bad Gateway | Invalid response from upstream server | Temporary issue, retry after delay |
503 | Service Unavailable | Server temporarily unavailable | System maintenance or overload, retry after delay |
504 | Gateway Timeout | Gateway did not receive timely response | Retry request, check for long-running operations |
Authentication Errors
Missing Merchant ID
Error Message: "Missing Merchant ID"
Cause: The merchant ID was not provided in the request.
Solution: Provide merchant ID using one of these methods:
Query Parameter:
?_mid=YOUR_MERCHANT_IDHTTP Header:
X-UC-Merchant-Id: YOUR_MERCHANT_IDCookie:
UltraCartMerchantID=YOUR_MERCHANT_IDStoreFront URL (Recommended):
https://YOUR_MERCHANT_ID.ultracartstore.com/rest/...
Example (jQuery):
jQuery.ajax({
url: '/rest/cart',
headers: {
'X-UC-Merchant-Id': 'YOUR_MERCHANT_ID',
'cache-control': 'no-cache'
},
dataType: 'json'
});
401 Unauthorized - Permission Denied
HTTP Status: 401
Error Response:
{
"error": {
"developer_message": "Permission Denied.",
"user_message": "Permission Denied."
},
"metadata": {}
}
Common Causes:
Invalid or missing API key
API key doesn't have required permissions
Using Simple API Key where OAuth is required
API access not enabled for the user account
Solutions:
For Simple API Key:
// PHP
$api_key = "YOUR_SIMPLE_API_KEY";
ultracart\v2\Configuration::getDefaultConfiguration()
->setApiKey('x-ultracart-simple-key', $api_key);
# Python
from ultracart.configuration import Configuration
configuration = Configuration()
configuration.api_key['x-ultracart-simple-key'] = 'YOUR_SIMPLE_API_KEY'
Enable API Access:
Log into secure.ultracart.com
Navigate to: Configuration → Manage Users → Edit User
Check "API Access" permission
Save changes
For OAuth Applications:
Ensure valid access token
Verify OAuth scopes match endpoint requirements
Check if token has expired and refresh if needed
Invalid API Credentials
Error Message: "Invalid credentials"
Cause: API key is incorrect or has been revoked.
Solution:
Verify API key in UltraCart admin panel
Regenerate API key if compromised
Check for extra spaces when copying API key
Ensure using correct environment (production vs. sandbox)
Validation Errors
400 Bad Request - Invalid JSON
Error Message: "Problems parsing JSON"
Cause: Request body contains malformed JSON.
Solutions:
Validate JSON syntax using a linter or validator
Ensure proper escaping of special characters
Check for trailing commas (not allowed in JSON)
Verify content-type header is set correctly
// Correct content-type header
headers: {
'Content-Type': 'application/json; charset=UTF-8'
}
400 Bad Request - Body Not a JSON Object
Error Message: "Body should be a JSON object"
Cause: Request body is not formatted as a JSON object.
Solution: Ensure request body is a valid JSON object:
// Incorrect - sending string
data: "some string"
// Correct - sending JSON object
data: JSON.stringify({
merchantId: 'DEMO',
email: 'customer@example.com'
})
422 Unprocessable Entity - Invalid Parameters
Error Message: "Invalid request" or "Invalid input"
Common Scenarios:
Wrong parameter type:
// Error: Expecting string but got array
{
"item_id": ["ITEM1", "ITEM2"] // Should be: "ITEM1"
}
Missing required fields:
// Error: Missing required email field
{
"firstName": "John",
"lastName": "Doe"
// email is required
}
Invalid field values:
// Error: Invalid credit card expiration
{
"creditCardExpirationMonth": 13 // Should be 1-12
}
Solution: Refer to API documentation for correct parameter types and required fields.
Cart Validation Errors
The /rest/cart/validate endpoint returns specific validation errors:
Request:
jQuery.ajax({
url: '/rest/cart/validate?check=billing&check=shipping&check=payment',
type: 'POST',
contentType: 'application/json; charset=UTF-8',
data: JSON.stringify(cart),
dataType: 'json'
});
Response (with errors):
[
"Email address is required",
"Billing first name is required",
"Credit card number is invalid"
]
Common Validation Checks:
billing- Billing address fieldsshipping- Shipping address fieldspayment- Payment method and card detailsitems- Cart items validitycoupons- Coupon code validitygiftCertificate- Gift certificate validation
Rate Limiting Errors
429 Too Many Requests
HTTP Status: 429
Headers Returned:
Retry-After: 60
Error Response:
{
"error": {
"developer_message": "Rate limit exceeded. Please retry after 60 seconds.",
"user_message": "Too many requests. Please try again later."
}
}
Rate Limits:
Endpoint Type | Rate Limit | Notes |
|---|---|---|
Most endpoints | Varies by endpoint | Standard rate limiting |
Item inventory ( | Max 1 call per 15 minutes | Strictly enforced |
Batch operations | 500 items max per request | Exceeding returns 400 error |
SDK Auto-Retry (PHP): The PHP SDK automatically retries when rate limits are hit:
// PHP SDK handles retry automatically when rate limit triggered
// Other SDKs to follow in future updates
Manual Retry Logic:
JavaScript:
async function retryRequest(requestFunc, maxRetries = 5) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await requestFunc();
if (response.status !== 429) {
return response;
}
// Get retry-after header if present
const retryAfter = response.headers.get('Retry-After');
const delay = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
} catch (error) {
if (attempt === maxRetries - 1) throw error;
}
}
throw new Error('Max retries exceeded');
}
Python:
import time
import random
def retry_request(request_func, max_retries=5):
for attempt in range(max_retries):
try:
response = request_func()
if response.status_code != 429:
return response
retry_after = response.headers.get('Retry-After')
delay = int(retry_after) if retry_after else (2 ** attempt)
time.sleep(delay + random.uniform(0, 1))
except Exception as e:
if attempt == max_retries - 1:
raise e
raise Exception("Max retries exceeded")
Best Practices:
Implement exponential backoff with jitter
Honor
Retry-Afterheader when presentCache frequently accessed data (items, allowed countries)
Batch requests when possible
Monitor API usage patterns
Cart and Checkout Errors
Missing Checkout Redirect
Common Mistake: Not redirecting to redirectToUrl after checkout.
Error: Order never completes, payment not processed.
Explanation: The /rest/cart/checkout endpoint is NOT the final step. After calling checkout successfully (no errors in response), you must redirect the browser to the URL found in checkoutResponse.redirectToUrl.
Correct Flow:
jQuery.ajax({
url: '/rest/cart/checkout',
type: 'POST',
contentType: 'application/json; charset=UTF-8',
data: JSON.stringify(checkoutRequest),
dataType: 'json'
}).done(function(checkoutResponse) {
if (!checkoutResponse.errors || checkoutResponse.errors.length === 0) {
// CRITICAL: Must redirect to complete order
window.location.href = checkoutResponse.redirectToUrl;
} else {
// Display errors to user
displayErrors(checkoutResponse.errors);
}
});
What happens during redirect:
Payment gateway processing
Fraud screening
Upsell gauntlet (if configured)
Order finalization
Receipt generation
If errors occur during redirect phase:
User is redirected back to
checkoutRequest.redirectOnErrorUrlThis is typically your checkout page
Error details are in URL parameters or session
Preorder Item Errors Overriding Other Errors
Issue: When cart contains preorder items, preorder warnings may hide validation errors.
Solution: Separate cart updates from checkout calls:
// Step 1: Update cart with items
jQuery.ajax({
url: '/rest/cart',
type: 'PUT',
data: JSON.stringify(cart),
// ...
}).done(function(updatedCart) {
// Step 2: Then call checkout
jQuery.ajax({
url: '/rest/cart/checkout',
type: 'POST',
data: JSON.stringify(checkoutRequest),
// ...
});
});
Hosted Fields Required (PCI 3.0)
Error Context: As of June 2015, credit card numbers cannot be sent directly to the API.
Solution: Use UltraCart Hosted Fields for PCI 3.0 compliance.
Old (No longer works):
cart.creditCardNumber = '4111111111111111'; // ❌ Not allowed
Correct (Hosted Fields):
// 1. Load Hosted Fields library
<script src="https://token.ultracart.com/hosted_fields/..."></script>
// 2. Initialize Hosted Fields
UltraCart.HostedFields.initialize({
// configuration
});
// 3. Tokenize card before checkout
UltraCart.HostedFields.tokenize(function(token) {
cart.creditCardToken = token; // ✅ Use token instead
// Proceed with checkout
});
Cart Session Expiration
Symptom: Cart ID becomes invalid, causing 404 errors.
Cause: Cart sessions expire after inactivity.
Solution:
Store
cartIdin browser cookieCreate new cart if existing cart returns 404
Implement cart recovery for logged-in customers
function getOrCreateCart() {
const savedCartId = getCookie('UltraCartCartId');
if (savedCartId) {
// Try to retrieve existing cart
return fetchCart(savedCartId).catch(error => {
if (error.status === 404) {
// Cart expired, create new one
return createNewCart();
}
throw error;
});
}
return createNewCart();
}
Arbitrary Unit Cost Errors
Error: Using arbitraryUnitCost on items not configured for it.
Cause: Item must be configured in UltraCart admin to allow arbitrary pricing.
Solution:
Configure item in admin: Items → Edit Item → Pricing
Enable "Allow Arbitrary Unit Cost"
Set min/max bounds if needed
// Now this will work
{
"item_id": "DONATION",
"quantity": 1,
"arbitraryUnitCost": 50.00
}
Distribution Center Not Configured for REST API
HTTP Status: 400
Headers:
HTTP/1.1 400
X-UltraCart-Request-Id: 8376DD8AC3EA6A019A4ADA5E291F43489
Content-Type: application/json; charset=UTF-8
UC-REST-ERROR: Distribution center is not configured for REST API transport.
Error Response:
{
"error": {
"developer_message": "Distribution center is not configured for REST API transport.",
"user_message": "Distribution center is not configured for REST API transport."
},
"metadata": {}
}
Cause: The distribution center is not properly configured to use REST API as its transmission mechanism.
Solution:
Step 1: Navigate to Distribution Center Settings
Log into secure.ultracart.com
Go to: Configuration → Checkout → Shipping → Distribution Centers
Direct URL:
https://secure.ultracart.com/merchant/configuration/shipping/distributionCenterListLoad.do
Click Edit next to the distribution center
Step 2: Verify Basic Configuration In the Distribution Center tab, ensure these required fields are filled:
Code
Name
Postal Code
State
Country
Step 3: Configure Transmission Mechanism
Click on the Transmission Mechanism tab
Set Transmission Method to: REST
In the Authorized Application (required) dropdown:
Select your authorized OAuth application
This links your API application to the distribution center
Important: Scroll to bottom and click Save
Step 4: Verify Configuration After saving, the distribution center should now accept REST API calls for:
Order creation via REST
Order status updates
Shipping notifications
Inventory management
Common Mistakes:
Forgetting to save after changing transmission method
Not having an authorized OAuth application created yet
Selecting wrong application from dropdown
Missing required fields in Distribution Center tab (prevents saving)
Create Authorized Application (if needed):
Navigate to: Configuration → OAuth Applications
Create new OAuth application
Grant necessary permissions (orders, shipping, etc.)
Return to Distribution Center settings
Select newly created application from dropdown
Verification Test:
// Test if distribution center is properly configured
// Attempt to create or update an order via REST API
// Should succeed without the 400 error
Related Errors:
If you haven't created an OAuth application yet, the "Authorized Application" dropdown will be empty
If the distribution center basic info is incomplete, you won't be able to save the transmission mechanism settings
Payment Processing Errors
These errors occur during the redirect phase after /rest/cart/checkout:
Credit Card Declined
User Message: "Your card was declined. Please use a different payment method."
Common Reasons:
Insufficient funds
Incorrect billing address (AVS mismatch)
Card expired
Card reported lost/stolen
Incorrect CVV
User Action: User is redirected back to redirectOnErrorUrl to try again.
Payment Gateway Timeout
Symptom: Order processing takes unusually long, then fails.