Skip to main content
How-to

UltraCart REST API Errors - Developer's Reference Guide

Table of Contents

  1. Overview

  2. Error Response Structure

  3. HTTP Status Codes

  4. Authentication Errors

  5. Validation Errors

  6. Rate Limiting Errors

  7. Cart and Checkout Errors

  8. Payment Processing Errors

  9. Resource Errors

  10. Server Errors

  11. Troubleshooting Tips

  12. Best Practices


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/v2

  • Version 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

CodeStatusDescription
200OKRequest succeeded, response contains data
201CreatedResource created successfully
204No ContentRequest succeeded, no content in response (e.g., delete operations)

4xx Client Error Codes

CodeStatusDescriptionCommon Causes
400Bad RequestMalformed request syntax or invalid parametersInvalid JSON, missing required fields, incorrect data types
401UnauthorizedAuthentication required or failedMissing/invalid API key, expired OAuth token, insufficient permissions
403ForbiddenValid request but server refuses to respondPermission denied, API access not enabled for user, IP restriction
404Not FoundResource does not existInvalid order ID, item ID, or endpoint URL; typos in URL
405Method Not AllowedHTTP method not supported for endpointUsing GET instead of POST, or vice versa
422Unprocessable EntityRequest well-formed but contains semantic errorsInvalid field values, failed business logic validation
Endpoint TypeRate LimitNotes
Most endpointsVaries by endpointStandard rate limiting
Item inventory (GET /items/inventory)Max 1 call per 15 minutesStrictly enforced
Batch operations500 items max per requestExceeding 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:

  1. Implement exponential backoff with jitter

  2. Honor Retry-After header when present

  3. Cache frequently accessed data (items, allowed countries)

  4. Batch requests when possible

  5. 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.redirectOnErrorUrl

  • This 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:

  1. Store cartId in browser cookie

  2. Create new cart if existing cart returns 404

  3. 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:

  1. Configure item in admin: Items → Edit Item → Pricing

  2. Enable "Allow Arbitrary Unit Cost"

  3. 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

  1. Log into secure.ultracart.com

  2. Go to: Configuration → Checkout → Shipping → Distribution Centers

    • Direct URL: https://secure.ultracart.com/merchant/configuration/shipping/distributionCenterListLoad.do
  3. 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

  1. Click on the Transmission Mechanism tab

  2. Set Transmission Method to: REST

  3. In the Authorized Application (required) dropdown:

    • Select your authorized OAuth application

    • This links your API application to the distribution center

  4. 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):

  1. Navigate to: Configuration → OAuth Applications

  2. Create new OAuth application

  3. Grant necessary permissions (orders, shipping, etc.)

  4. Return to Distribution Center settings

  5. 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.

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:

  1. Invalid Order ID:
// Error: Order doesn't exist
orderApi.getOrder('INVALID-ORDER-ID', expansion)
  1. Invalid Item ID:
// Error: Item not found
itemApi.getItem('NON_EXISTENT_ITEM')
  1. Typo in endpoint URL:
// Error: Wrong endpoint
'/rest/v2/order/DEMO-123' // ❌ Missing 's'
'/rest/v2/orders/DEMO-123' // ✅ Correct
  1. 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:

  1. Check authentication credentials

  2. Verify API key has required scopes/permissions

  3. Confirm user has necessary role (e.g., organization owner)


Server Errors

500 Internal Server Error

Cause: Unexpected server-side error.

Action:

  1. Check request for malformed data

  2. Retry request after brief delay

  3. If persists, contact UltraCart support with request details

  4. Provide request ID if available

502 Bad Gateway / 503 Service Unavailable

Cause: Server temporarily unavailable or under maintenance.

Action:

  1. Wait and retry after exponential delay

  2. Check UltraCart status page

  3. 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

  1. 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

  2. Examine response headers

    • Error messages often in response headers

    • Look for X-UC-Error or similar headers

  3. Enable debug mode (SDK-specific)

// PHP - Enable debug mode
$client = new GuzzleHttp\Client(['verify' => true, 'debug' => true]);
  1. 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

  2. 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

  1. Not handling errors in response objects

    • Always check for error or errors field

    • Don't assume success based on HTTP 200 status

  2. Forgetting merchant ID

    • Error: "Missing Merchant ID"

    • Solution: Always provide via header, query param, cookie, or StoreFront URL

  3. Skipping checkout redirect

    • Critical: Must redirect to redirectToUrl

    • Order will not complete without this step

  4. Using deprecated API version

    • Version 1 is legacy

    • Use Version 2 with SDKs for all new development

  5. Incorrect content-type header

// Wrong
headers: { 'Content-Type': 'text/plain' }

// Correct
headers: { 'Content-Type': 'application/json; charset=UTF-8' }
  1. Not URL encoding parameters
// Wrong
`/rest/v2/item/${itemId}` // If itemId contains special chars

// Correct
`/rest/v2/item/${encodeURIComponent(itemId)}`

Getting Help

Community Support:

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:

  1. Full error message (developer_message and user_message)

  2. Request details (endpoint, method, parameters)

  3. Response body and headers

  4. Steps to reproduce

  5. API call history log entry (from UltraCart admin)

  6. SDK version and language


Best Practices

Error Handling

  1. Always check for errors first:
if (apiResponse.error) {
// Handle error
return;
}
// Process success response
  1. 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);
  1. Implement retry logic with backoff:
  • Use exponential backoff for retries

  • Add jitter to prevent thundering herd

  • Respect Retry-After header

  1. 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

  1. 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
  1. Use OAuth for third-party integrations:
  • Simple API Key for internal/server-side use

  • OAuth 2.0 for apps that access customer data

  1. Restrict API users:
  • Create dedicated API user

  • Grant only "API Access" permission

  • Restrict by IP address if possible

  1. Use HTTPS always:
  • All API endpoints require HTTPS

  • Never send credentials over HTTP

Performance

  1. Use expansion parameters wisely:
// Only request fields you need
expansion = "items,summary" // ✅ Minimal payload

// Avoid requesting everything
expansion = "*" // ❌ Largest payload
  1. Implement caching:
// Cache rarely-changing data
const allowedCountries = await cache.get('countries') ||
await fetchAndCache('countries');
  1. Batch operations when possible:
// Batch order retrieval
orderApi.getOrdersBatch({
order_ids: ['ORDER1', 'ORDER2', 'ORDER3']
});
  1. Monitor API usage:
  • Track request counts

  • Set up alerts near rate limits

  • Optimize inefficient code patterns

Development Workflow

  1. Use demo merchant ID for testing:

    • Merchant ID: DEMO

    • Test without affecting production

  2. Test in sandbox before production:

    • Validate integrations thoroughly

    • Test error scenarios

    • Verify payment processing

  3. 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
  1. Follow SDK conventions:
  • Use language-specific SDK patterns

  • Leverage built-in retry logic (PHP SDK)

  • Follow SDK documentation for your language


Version History

  • Version 2 (Current) - REST API with OpenAPI specs and SDKs

    • Released: 2015+

    • Languages: PHP, Python, Java, C#, JavaScript/TypeScript, Ruby

    • Features: Comprehensive error handling, retry logic, OAuth support

  • Version 1 (Legacy) - Original REST API

    • Status: Maintained but no new features

    • Use: Only for legacy implementations

    • Migration: All new projects should use Version 2


Quick Reference

Most Common Errors

ErrorHTTP CodeQuick Fix
Missing Merchant ID400Add X-UC-Merchant-Id header
Permission Denied401Enable API Access for user
Rate Limited429Wait and retry with backoff
Order Not Found404Verify order ID is correct
Invalid JSON400Validate JSON syntax
Distribution Center Not Configured400Set transmission method to REST, select authorized app
Credit Card DeclinedN/AUser must try different card

Essential Headers

// Minimum required headers
{
'X-UC-Merchant-Id': 'YOUR_MERCHANT_ID',
'Content-Type': 'application/json; charset=UTF-8',
'cache-control': 'no-cache'
}

// For Simple API Key authentication
{
'x-ultracart-simple-key': 'YOUR_API_KEY'
}

// For OAuth authentication
{
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}

Key Endpoints

EndpointMethodPurpose
/rest/v2/checkout/cartGETRetrieve cart
/rest/v2/checkout/cartPUTUpdate cart
/rest/v2/checkout/cart/checkoutPOSTSubmit checkout
/rest/v2/checkout/cart/validatePOSTValidate cart
/rest/v2/order/orders/{order_id}GETGet order details
/rest/v2/item/items/{item_id}GETGet item details

Additional Resources


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-Agent header 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:


Last Updated: November 2025
API Version: 2.0
Guide Version: 1.0

Was this page helpful?