Quoting API
The MoveJoy Quoting API provides a programmatic interface to the same quote engine used by the AI voice agent. Use it to embed real-time estimates on your website, CRM, or any external system.
Base URL
https://api.movejoy.comAll endpoints are prefixed with /api/v1/quotes.
Authentication
All quoting API requests require an API key passed in the Authorization header.
Authorization: Bearer mqk_live_your_api_key_hereAPI keys are issued per organization and are scoped to either the live or test environment.
Key Format
mqk_{environment}_{random}Examples: mqk_live_abc123..., mqk_test_abc123...
Generating an API Key
API keys are managed from the dashboard under Settings > API Keys. Generate a live key for production use and a test key for development.
Security
- Never expose your API key in client-side code or public repositories.
- Keys are stored as SHA-256 hashes. A lost key cannot be recovered; generate a new one.
- Keys can be revoked from the dashboard at any time.
Rate Limits
Rate limits are applied per API key. Limits vary by subscription plan and are shown in the Settings > API Keys section of the dashboard.
Rate limit status is returned in response headers on every request:
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 28
X-RateLimit-Reset: 1711900800When the limit is exceeded, the API returns HTTP 429 with a retryAfter field in the response body (in seconds).
Endpoints
Health Check
GET /api/v1/quotes/healthNo authentication required. Returns 200 OK if the API is operational.
Response
{ "status": "ok", "version": "1.0.0" }List Service Types
GET /api/v1/quotes/servicesReturns all active service types configured for your organization. Use the code values from this response in estimate requests.
Response
{
"services": [
{
"code": "local_move",
"name": "Local Move",
"category": "residential",
"pricing_type": "hourly",
"description": "Local moves within 50 miles"
},
{
"code": "long_distance",
"name": "Long Distance Move",
"category": "residential",
"pricing_type": "mileage",
"description": null
}
]
}Calculate Estimate
POST /api/v1/quotes/estimate
Content-Type: application/json
Authorization: Bearer mqk_live_...Calculates a quote for a move based on your configured service type pricing.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
service_code | string | Yes | Service type code (from /services endpoint) |
origin | string | Yes | Origin address or ZIP code |
destination | string | Yes | Destination address or ZIP code |
estimated_hours | number | No | Estimated job duration in hours (0.5 to 48) |
move_size | string | No | One of: studio, 1br, 2br, 3br, 4br, 5br |
addons | string[] | No | List of addon type codes to include |
addon_quantities | object | No | Map of addon code to quantity, e.g. { "stairs": 2 } |
Example Request
{
"service_code": "local_move",
"origin": "33101",
"destination": "33130",
"estimated_hours": 4,
"move_size": "2br",
"addons": ["packing"],
"addon_quantities": { "packing": 1 }
}Response
{
"success": true,
"quote": {
"total": 490.00,
"currency": "USD",
"summary": "4 hours @ $85.00/hr",
"minimumFloorApplied": false,
"distance": {
"miles": 6.2,
"travelTimeMinutes": 18,
"travelTime": "18 min"
},
"breakdown": [
{ "label": "Labor (4 hrs)", "amount": 340.00, "type": "hourly" },
{ "label": "Packing Service", "amount": 150.00, "type": "addon" }
],
"service": {
"name": "Local Move",
"code": "local_move",
"pricing_type": "hourly"
}
}
}Response Fields
| Field | Type | Description |
|---|---|---|
quote.total | number | Final quote amount in the service type's currency |
quote.currency | string | ISO currency code, e.g. USD |
quote.summary | string | Human-readable summary of the calculation |
quote.minimumFloorApplied | boolean | Whether the minimum quote amount was enforced |
quote.distance.miles | number | Driving distance between origin and destination |
quote.distance.travelTimeMinutes | number | Estimated driving time in minutes |
quote.distance.travelTime | string | Human-readable travel time, e.g. "18 min" |
quote.breakdown | LineItem[] | Itemized list of charges |
quote.service.name | string | Service type display name |
quote.service.code | string | Service type code |
quote.service.pricing_type | string | Pricing model used |
LineItem fields:
| Field | Type | Description |
|---|---|---|
label | string | Display label for the line item |
amount | number | Dollar amount for this line item |
type | string | One of: base, hourly, overtime, mileage, travel_time, fuel_surcharge, addon |
Error Response
{
"success": false,
"error": "Service type not found",
"code": "SERVICE_NOT_FOUND"
}Pricing Type Behavior
Hourly
Quote is calculated as: base_hourly_rate * max(estimated_hours, minimum_hours).
Overtime applies if estimated_hours > overtime_threshold_hours. Hours above the threshold are multiplied by overtime_rate_multiplier (e.g., 1.5).
Flat
Quote is the configured base_flat_rate regardless of distance or duration.
Mileage
Quote is calculated as: base_flat_rate + (distance_miles * mileage_rate).
Distance is resolved via real-time routing data using the provided origin and destination.
Hybrid
Combines hourly labor and mileage. Quote is: (base_hourly_rate * estimated_hours) + (distance_miles * mileage_rate).
Add-on Pricing Units
| Unit | Description |
|---|---|
flat | Fixed price per add-on item |
per_hour | Multiplied by estimated_hours |
per_item | Multiplied by the quantity in addon_quantities |
per_flight | Multiplied by the quantity (typically flights of stairs) |
Integration Examples
JavaScript (fetch)
const response = await fetch('https://api.movejoy.com/api/v1/quotes/estimate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer mqk_live_your_key_here',
},
body: JSON.stringify({
service_code: 'local_move',
origin: '33101',
destination: '33130',
estimated_hours: 3,
}),
})
const data = await response.json()
console.log(data.quote.total)cURL
curl -X POST https://api.movejoy.com/api/v1/quotes/estimate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer mqk_live_your_key_here" \
-d '{
"service_code": "local_move",
"origin": "33101",
"destination": "33130",
"estimated_hours": 3
}'Using the Test Environment
Replace mqk_live_ keys with mqk_test_ keys to use the test environment. Test requests do not affect live data and are not counted toward production rate limits.