Error Reference
A catalogue of the failures merchants actually hit against the REST API, what causes each one, and how to fix it.
Errors covers the error object and what each status code means. This page starts where that one stops: the specific failures, in the order you are likely to meet them.
Reading an error
Every failed call returns an error object carrying a developer_message to log and a
user_message that is safe to show a customer. Errors documents the full shape
and the status-code semantics.
Two things trip people up. UltraCart application errors arrive on apiResponse.error with a
200, so checking the HTTP status alone is not enough. And developer_message is the one worth
logging; user_message is deliberately vague.
Handling an error in each SDK
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
Rate limits and retries
Rate limiting documents the account-wide limits and the 429 response.
Some endpoints carry their own tighter limits on top of those:
| Endpoint Type | Rate Limit | Notes |
|---|---|---|
| Most endpoints | Varies by endpoint | Standard rate limiting |
Item inventory (GET /items/inventory) | Max 1 call per 15 minutes | Strictly enforced |
| Batch operations | 500 items max per request | Exceeding returns 400 error |
The PHP SDK retries automatically when a rate limit is hit. Pass max_retry_seconds to
usingApiKey() to set the budget. The other SDKs leave retrying to you.
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 present -
Cache frequently accessed data (items, allowed countries)
-
Batch requests when possible
-
Monitor API usage patterns
Cart and Checkout Errors
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 cookie -
Create 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
- Direct URL:
-
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 surface while the gateway processes the payment, not when the call returns:
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.
Cause: Payment gateway not responding.
UltraCart Handling:
-
Timeout handled during redirect phase
-
User redirected back to retry
-
No browser timeout because processing happens server-side
CVV Validation Failure
Error: CVV verification failed.
Notes:
-
UltraCart does not store CVV values
-
If using stored credit cards, configure gateway to not require CVV
-
For new cards, CVV is always required unless gateway configured otherwise
Resource Errors
404 Not Found - Resource Does Not Exist
Common Causes:
- Invalid Order ID:
// Error: Order doesn't exist
orderApi.getOrder('INVALID-ORDER-ID', expansion)
- Invalid Item ID:
// Error: Item not found
itemApi.getItem('NON_EXISTENT_ITEM')
- Typo in endpoint URL:
// Error: Wrong endpoint
'/rest/v2/order/DEMO-123' // ❌ Missing 's'
'/rest/v2/orders/DEMO-123' // ✅ Correct
- Trailing slash causes 404:
// Error: Trailing slash
'/rest/v2/orders/' // ❌
'/rest/v2/orders' // ✅
Solution: Verify:
-
Resource identifier is correct
-
Endpoint URL matches API documentation
-
No trailing slashes
-
Proper URL encoding of parameters
404 for Private Resources (Security Measure)
Note: UltraCart returns 404 (not 403) for private resources you don't have access to, avoiding confirmation of their existence.
If you get 404 for a resource you know exists:
-
Check authentication credentials
-
Verify API key has required scopes/permissions
-
Confirm user has necessary role (e.g., organization owner)
Server Errors
500 Internal Server Error
Cause: Unexpected server-side error.
Action:
-
Check request for malformed data
-
Retry request after brief delay
-
If persists, contact UltraCart support with request details
-
Provide request ID if available
502 Bad Gateway / 503 Service Unavailable
Cause: Server temporarily unavailable or under maintenance.
Action:
-
Wait and retry after exponential delay
-
Check UltraCart status page
-
If prolonged, contact support
Example Retry Logic:
async function robustRequest(requestFunc) {
const delays = [1000, 2000, 5000, 10000]; // milliseconds
for (let delay of delays) {
try {
const response = await requestFunc();
if (response.status < 500) {
return response;
}
} catch (error) {
// Log error
}
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error('Service unavailable after retries');
}
Troubleshooting Tips
Debugging Checklist
-
Check browser console (for frontend issues)
-
Open developer tools (F12)
-
Look for JavaScript errors
-
Inspect network tab for API calls
-
Check request/response headers and payloads
-
-
Examine response headers
-
Error messages often in response headers
-
Look for
X-UC-Erroror similar headers
-
-
Enable debug mode (SDK-specific)
// PHP - Enable debug mode
$client = new GuzzleHttp\Client(['verify' => true, 'debug' => true]);
-
Use Server-Side Logging
-
Enable in UltraCart admin: Developer Tools → Call History Log
-
Navigate to: Configuration → Manage Users → Edit User
-
Grant "API Access" permission
-
View last 100 API calls with full details
-
-
Check API call history
-
Log into secure.ultracart.com
-
Go to Developer Tools → Call History Log
-
View request/response details
-
Examine transmission logs for errors
-
Common Pitfalls
-
Not handling errors in response objects
-
Always check for
errororerrorsfield -
Don't assume success based on HTTP 200 status
-
-
Using deprecated API version
-
Version 1 is legacy
-
Use Version 2 with SDKs for all new development
-
-
Incorrect content-type header
// Wrong
headers: { 'Content-Type': 'text/plain' }
// Correct
headers: { 'Content-Type': 'application/json; charset=UTF-8' }
- Not URL encoding parameters
// Wrong
`/rest/v2/item/${itemId}` // If itemId contains special chars
// Correct
`/rest/v2/item/${encodeURIComponent(itemId)}`
Getting Help
Community Support:
-
Post issues on GitHub: https://github.com/UltraCart
-
Check existing issues for solutions
-
Response time: 24-48 hours
Professional Services:
-
Rate: $100/hour (1 hour minimum)
-
For API development questions and troubleshooting
-
Contact via UltraCart admin panel
What to Include in Support Requests:
-
Full error message (developer_message and user_message)
-
Request details (endpoint, method, parameters)
-
Response body and headers
-
Steps to reproduce
-
API call history log entry (from UltraCart admin)
-
SDK version and language
Best Practices
Error Handling
- Always check for errors first:
if (apiResponse.error) {
// Handle error
return;
}
// Process success response
- Log errors appropriately:
// Log technical details server-side
console.error('API Error:', apiResponse.error.developer_message);
// Show user-friendly message to customer
displayMessage(apiResponse.error.user_message);
- Implement retry logic with backoff:
-
Use exponential backoff for retries
-
Add jitter to prevent thundering herd
-
Respect
Retry-Afterheader
- Handle errors gracefully:
try {
const result = await apiCall();
return result;
} catch (error) {
if (error.status === 429) {
// Rate limited - retry later
await retryWithBackoff();
} else if (error.status >= 500) {
// Server error - show maintenance message
showMaintenanceMessage();
} else {
// Client error - show specific message
showErrorMessage(error.message);
}
}
Security
- Never expose API keys in client-side code:
// ❌ WRONG - API key in browser
const API_KEY = 'your-api-key-here';
// ✅ CORRECT - API key on server only
// Use OAuth for browser-based apps
- Use OAuth for third-party integrations:
-
Simple API Key for internal/server-side use
-
OAuth 2.0 for apps that access customer data
- Restrict API users:
-
Create dedicated API user
-
Grant only "API Access" permission
-
Restrict by IP address if possible
- Use HTTPS always:
-
All API endpoints require HTTPS
-
Never send credentials over HTTP
Performance
- Use expansion parameters wisely:
// Only request fields you need
expansion = "items,summary" // ✅ Minimal payload
// Avoid requesting everything
expansion = "*" // ❌ Largest payload
- Implement caching:
// Cache rarely-changing data
const allowedCountries = await cache.get('countries') ||
await fetchAndCache('countries');
- Batch operations when possible:
// Batch order retrieval
orderApi.getOrdersBatch({
order_ids: ['ORDER1', 'ORDER2', 'ORDER3']
});
- Monitor API usage:
-
Track request counts
-
Set up alerts near rate limits
-
Optimize inefficient code patterns
Development Workflow
-
Use demo merchant ID for testing:
-
Merchant ID:
DEMO -
Test without affecting production
-
-
Test in sandbox before production:
-
Validate integrations thoroughly
-
Test error scenarios
-
Verify payment processing
-
-
Keep SDKs updated:
# Check for updates regularly
composer update ultracart/rest_api_v2_sdk_php
pip install --upgrade ultracart-rest-api-v2
npm update ultracart_rest_api_v2_typescript
- Follow SDK conventions:
-
Use language-specific SDK patterns
-
Use the built-in retry logic (PHP SDK)
-
Follow SDK documentation for your language
Quick Reference
Most Common Errors
| Error | HTTP Code | Quick Fix |
|---|---|---|
| Permission Denied | 401 | Enable API Access for user |
| Rate Limited | 429 | Wait and retry with backoff |
| Order Not Found | 404 | Verify order ID is correct |
| Invalid JSON | 400 | Validate JSON syntax |
| Distribution Center Not Configured | 400 | Set transmission method to REST, select authorized app |
| Credit Card Declined | N/A | User must try different card |
Essential Headers
// For Simple API Key authentication
{
'x-ultracart-simple-key': 'YOUR_API_KEY'
}
// For OAuth authentication
{
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}
Key Endpoints
| Endpoint | Method | Purpose |
|---|---|---|
/rest/v2/checkout/cart | GET | Retrieve cart |
/rest/v2/checkout/cart | PUT | Update cart |
/rest/v2/checkout/cart/checkout | POST | Submit checkout |
/rest/v2/checkout/cart/validate | POST | Validate cart |
/rest/v2/order/orders/{order_id} | GET | Get order details |
/rest/v2/item/items/{item_id} | GET | Get item details |
Additional Resources
-
API Reference: every operation, generated from the OpenAPI spec
-
Rate limiting: account limits and the 429 response
-
SDKs & Samples: install and authenticate an SDK
-
SDK Samples: https://github.com/UltraCart/sdk_samples
-
GitHub Repositories: https://github.com/UltraCart
FAQ
Q: Why are my REST API requests blocked (403 error) when using Claude Code or another AI coding tool?
A: UltraCart may block REST API requests when the application sends a generic Python user agent, such as the default user agent generated by some scripts, libraries, or AI coding tools. UltraCart’s firewall does not allow requests that appear to come from generic Python scripts because they can resemble automated scraping or abusive traffic.
To avoid this issue, configure your REST API application to send a more descriptive application user agent. For example:
OpenAPI-Generator/4.1.91/python
When using tools such as Claude Code, review the generated HTTP client code and confirm that the User-Agent header is set explicitly. The user agent should identify the application or SDK rather than relying on a default Python value.
Example header:
User-Agent: OpenAPI-Generator/4.1.91/python
Tip: If your API requests suddenly receive firewall-related errors or appear to be blocked before reaching the UltraCart REST API, check the
User-Agentheader first. A generic Python user agent is a common cause when the client code was generated or modified by an AI coding tool.
Support
Free Support:
-
GitHub Issues: Post technical questions
-
Documentation: Comprehensive guides and examples
-
Community: Developer forums
Paid Support:
-
Professional Services: $100/hour
-
Custom integration assistance
-
Priority troubleshooting
Contact:
-
Email: support@ultracart.com
-
Portal: secure.ultracart.com
-
Phone: Available in admin panel
Last Updated: November 2025
API Version: 2.0
Guide Version: 1.0