SmarterRisk Order Intake API

Overview

The SmarterRisk Order Intake API allows Insurance Partners to programmatically submit risk assessment orders on behalf of their clients. Orders placed via the API follow the same workflow as orders placed through the partner dashboard — your client receives an invitation email, completes their risk assessment, and results appear in your partner dashboard.

Base URL: https://app.smarterrisk.com

V1 Scope

Version 1 is an order intake API.

  • Supported: Submit a new order, retrieve the saved order record by orderId
  • Not supported: Validation-only endpoints, quote/estimate endpoints, webhook callbacks, or API retrieval of risk reports, scores, recommendations, forms, or assessment results

Stability: V1 is stable. Breaking changes will only ship in a new version (v2). Non-breaking additions (new response fields, new optional request fields) may be added to v1 without notice. We recommend your integration ignore unknown response fields gracefully.


Quick Start

Get your first sandbox order submitted in under 5 minutes.

Step 1 — Get your sandbox API key:

  1. Log in to your Partner Dashboard at https://app.smarterrisk.com
  2. Go to My Account
  3. Click the API Integration tab
  4. Under Sandbox, click Generate Sandbox Key
  5. Copy the key immediately — it is shown only once

Step 2 — Submit a test order:

curl -X POST https://app.smarterrisk.com/api/v1/order-intake \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_SANDBOX_KEY" \
  -d '{
    "clientEmail": "test@example.com",
    "businessName": "Test Company",
    "contactName": "Jane Smith",
    "lines": ["WC"],
    "policyNumber": "TEST-001"
  }'

Step 3 — Check the response:

{
  "message": "Order received successfully",
  "orderId": "ORD-1234567890-ABCDE1234",
  "status": "pending",
  "plan": "bright",
  "orderCostCents": 0,
  "orderCost": "$0.00",
  "sandbox": true
}

Sandbox orders are saved and displayed in the Partner Dashboard GUI under “Current Client Orders” when the sandbox mode is toggled on. But no email is sent, no charge is made, and no client account is created. When you’re ready, generate a live key and swap it in.


Requirements

  • An active SmarterRisk Partner subscription (Legacy Pay as You Go Accounts are not supported)
  • An API key generated from your Partner Account page

Authentication

All requests must include your API key as a Bearer token in the Authorization header.

Authorization: Bearer YOUR_API_KEY

Managing API Keys

  1. Log in to your Partner Dashboard
  2. Go to My AccountAPI Integration
  3. Click Generate Key (live) or Generate Sandbox Key (sandbox)
  4. Give the key a friendly name for identification
  5. Copy the key immediately — it is shown only once

Key limits:

TypeMax Active KeysNotes
Live3Each key tracks its own usage and quota
Sandbox1Generating a new sandbox key replaces the previous one

You can revoke and regenerate keys at any time from the same page.

Security: Never expose your API key in client-side code (browser JavaScript, mobile apps). If you are building a public-facing intake form, keep your API key on your server and proxy requests through your own backend.


Endpoints

MethodPathDescription
POST/api/v1/order-intakeSubmit a new order
GET/api/v1/orders/:orderIdRetrieve the saved order record

Submit an Order

POST /api/v1/order-intake

Headers

HeaderValueRequired
AuthorizationBearer YOUR_API_KEYYes
Content-Typeapplication/jsonYes
Idempotency-KeyUnique string (UUID v4 recommended, max 128 characters)No

Idempotency

To safely retry a request without creating a duplicate order, include an Idempotency-Key header.

Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
  • Scope is per API key
  • Only 2xx responses are cached and replayed
  • Replayed responses include the header X-Idempotency-Replayed: true
  • The response echoes back your Idempotency-Key header
  • Reuse the same key only for retries of the same request body. Reusing a key with a different body is not supported
  • Idempotency keys are valid for 24 hours. After that, the same key will be treated as a new request
  • Idempotency is a best-effort safeguard for retry protection

Request Body

{
  "clientEmail": "jane@acmecorp.com",
  "businessName": "Acme Corp",
  "contactName": "Jane Smith",
  "lines": ["GL", "PR"],
  "policyNumber": "POL-12345",
  "numLocations": 2,
  "photosRequired": false,
  "upgradeSmart": false,
  "upgradeIntelligent": false,
  "thirdPartyEmail": "broker@example.com"
}

Request Rules

  • The request body must be a single JSON object using the exact field names shown below
  • Field names and enum values are case-sensitive
  • Unknown fields are rejected with 400 VALIDATION_ERROR
  • Required string fields reject empty strings

Fields

FieldTypeRequiredDescription
clientEmailstringYesClient’s email address. Used to create the client account.
businessNamestringYesClient’s business name (max 200 characters).
contactNamestringYesFull name of the primary contact (max 100 characters).
linesarrayYesArray of uppercase coverage codes to assess. See Coverage Lines.
policyNumberstringYesPolicy or reference number for your records (max 50 characters).
numLocationsintegerNoNumber of additional locations beyond the 1 included. Send 0 for a single-location order. Range: 0–10. Default: 0.
photosRequiredbooleanNoWhether photo uploads are required. Requires Smart or Intelligent plan — include upgradeSmart: true or upgradeIntelligent: true. Not available for FL/CL-only orders. Default: false.
upgradeSmartbooleanNoUpgrade to Smart plan. Default: false.
upgradeIntelligentbooleanNoUpgrade to Intelligent plan. Default: false. See Plan Levels for account-type rules.
thirdPartyEmailstringNoA single email address to receive an “order placed” notification (e.g. a broker). This person does not receive the assessment or results — only a notification that an order was submitted.

Location Counting

Every order includes 1 primary location automatically. The numLocations field specifies additional locations on top of that.

numLocations valueTotal locations assessed
0 (default)1
12
56
1011 (maximum)

Common mistake: If your client has 3 locations, send numLocations: 2 (not 3).

Assessment by Insurance Line

CodeDescription
WCWorkers Compensation
PRProperty
GLGeneral Liability
FLFleet
CLContractors Liability

Rules:

  • At least one line is required
  • Codes must be uppercase: WC, PR, GL, FL, CL
  • GL (General Liability) requires PR (Property) to also be included
  • photosRequired is not available for orders that include only FL and/or CL

Plan Levels

The plan determines what your client can access after completing their assessment.

PlanHow to requestWhat the client gets
BrightDefault (no upgrade flags)Risk assessment + recommendations
SmartupgradeSmart: trueBright + risk score + full risk report + recommendation updates
IntelligentupgradeSmart: true + upgradeIntelligent: trueSmart + all features (forms, policy builder, training director)

Account-type behavior:

  • MGA / Agency accounts: To request Intelligent, you must send both upgradeSmart: true and upgradeIntelligent: true.
  • Insurer accounts: Start at Smart by default. Send upgradeIntelligent: true alone to go straight to Intelligent — upgradeSmart is not required.

Tip: If you’re unsure of your account type, always send both upgradeSmart: true and upgradeIntelligent: true when you want Intelligent. This works correctly for all account types.

Success Response — 201 Created

{
  "message": "Order received successfully",
  "orderId": "ORD-1234567890-ABCDE1234",
  "status": "pending",
  "plan": "smart",
  "orderCostCents": 5000,
  "orderCost": "$50.00"
}
FieldDescription
orderIdUnique order identifier. Use this to check status via GET /api/v1/orders/:orderId.
statusAlways "pending" on creation.
planThe plan assigned to this order ("bright", "smart", or "intelligent").
orderCostCentsOrder cost in cents as an integer (e.g. 5000 = $50.00). 0 for Bright plan orders.
orderCostOrder cost as a formatted string (e.g. "$50.00"). "$0.00" for Bright plan orders.

Sandbox orders include an additional "sandbox": true field.

What Happens After a Successful Order

  1. Your client receives an invitation email with a link to complete their risk assessment
  2. The order appears in your Partner Dashboard under Current Client Orders
  3. Once your client completes the assessment, results are available in your dashboard

Downstream artifacts (reports, scores, recommendations) are not returned by the v1 API. Use your Partner Dashboard to view results.

Degraded Response — 202 Accepted

In rare cases, the order is accepted but a downstream step fails. The API returns 202 instead of 201. If Stripe already charged your account, the response includes invoiceID.

Do not retry 202 responses. The order may already be partially processed. Contact support with the orderId and invoiceID (if present). Support is automatically alerted when this occurs.

StatusMeaning
payment_captured_client_failedCharged, but client account creation failed
payment_captured_partner_save_failedCharged, but partner record could not be saved
payment_captured_queue_failedCharged, but background processing could not start
queue_dispatch_failedNo charge, but background processing could not start

Example:

{
  "message": "Payment was captured but client account setup failed. Your account has been charged and support has been notified. Please contact support referencing your order ID.",
  "orderId": "ORD-1234567890-ABCDE1234",
  "status": "payment_captured_client_failed",
  "invoiceID": "in_abc123"
}

Pricing

  • Bright plan orders are always no charge: orderCostCents: 0
  • Smart and Intelligent pricing is calculated server-side using the same logic as the partner dashboard, including subscriber discounts, line surcharges, and plan add-ons
  • The authoritative billed amount is the orderCostCents / orderCost returned in the 201 response
  • There is no quote or estimate endpoint in v1 — contact your account manager for your rate card

Check Order Status

GET /api/v1/orders/:orderId

Retrieve the saved order record using the orderId returned by POST /api/v1/order-intake.

curl https://app.smarterrisk.com/api/v1/orders/ORD-1234567890-ABCDE1234 \
  -H "Authorization: Bearer YOUR_API_KEY"

Success Response — 200 OK

{
  "orderId": "ORD-1234567890-ABCDE1234",
  "status": "pending",
  "plan": "smart",
  "orderType": "assessment",
  "createdAt": "2026-03-05T18:00:00.000Z",
  "clientInfo": {
    "email": "jane@acmecorp.com",
    "businessName": "Acme Corp"
  },
  "serviceDetails": {
    "lines": ["GL", "PR"],
    "numLocations": 2
  }
}

Sandbox orders include "sandbox": true.

V1 Limitation

This endpoint returns the saved order record from the intake service. In normal flows, status remains pending. It does not reflect assessment completion, report availability, or any downstream progress. Degraded statuses are returned if the order encountered a processing issue.

Note: orderCostCents and orderCost are only returned in the POST response. The GET endpoint returns the saved order record without pricing.

Order Status Values

StatusMeaningAction
pendingOrder saved successfullyNo action needed
payment_captured_client_failedCharged, client creation failedContact support — do not retry
payment_captured_partner_save_failedCharged, partner record save failedContact support — do not retry
payment_captured_queue_failedCharged, background processing failedContact support — do not retry
queue_dispatch_failedNo charge, background processing failedContact support — do not retry
payment_captured_persistence_failedEmergency: charged, order record could not be savedContact support immediately

Error — 404

{ "message": "Order not found", "error": "ORDER_NOT_FOUND" }

Returns 404 if the order doesn’t exist or belongs to a different company.


Usage & Quota

Each API key tracks monthly and total order counts. Your account administrator can set a monthly quota per key from the Partner Account page.

Usage is visible in the API Integration section, shown per key (e.g. “42 / 500 orders this month”). Counts reset automatically on the first of each calendar month. All successful live orders count toward the quota.

If the quota is exceeded:

{
  "message": "Monthly order quota of 500 reached. Please contact support to increase your limit.",
  "error": "MONTHLY_QUOTA_EXCEEDED"
}

API Budget

Your account administrator can set a monthly dollar budget for API orders from the Partner Account page. Each order is costed using the same pricing as the partner dashboard. If an order would cause your account to exceed the budget, it is rejected before any processing or charge occurs.

Budget spend and remaining balance are visible on the Partner Account page. Spend resets on the first of each calendar month. Changing the budget limit does not reset current-month spend.

If the budget would be exceeded:

{
  "message": "This order will exceed your monthly budget. Current spend: $450.00, Order cost: $75.00, Budget limit: $500.00. Please contact your admin to update the budget.",
  "error": "BUDGET_LIMIT_REACHED"
}

Rate Limits

Each API key is limited to 60 requests per minute (per key, not per account).

Every response includes rate limit headers:

HeaderDescription
X-RateLimit-LimitMaximum requests per minute for this key
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp (seconds) when the window resets

When the limit is exceeded, the API returns 429 with a Retry-After header indicating seconds to wait.


Sandbox Mode

Use a sandbox API key to test your integration without triggering real processing.

How to get a sandbox key: Partner Dashboard → My Account → API Integration → Sandbox → Generate Sandbox Key.

What sandbox mode does:

  • Uses the same base URL and endpoints as live
  • Returns a real 201 response with "sandbox": true
  • Order is saved and visible in the Partner Dashboard when Sandbox View is toggled on
  • No invitation email is sent
  • No third-party notification is sent
  • No order processing, Stripe charge, SQS dispatch, or client account creation occurs
  • Sandbox orders do not count against live monthly quota or live API budget
  • Sandbox orders are automatically deleted after 30 days

What works identically to live: Authentication, validation, error handling, rate limiting, and all request/response schemas.

Use sandbox to verify your integration end-to-end before switching to a live key.


Error Responses

All errors return a JSON body with message and error fields. All responses use Content-Type: application/json.

400 — Validation Error

{
  "message": "Business Name — Business Name is required",
  "error": "VALIDATION_ERROR",
  "errors": [
    {
      "field": "businessName",
      "label": "Business Name",
      "message": "Business Name is required",
      "detail": "Business Name — Business Name is required"
    }
  ]
}

The top-level message is always the first error as a human-readable string. The errors array contains all validation issues — useful for mapping errors to form fields.

Common validation errors:

ErrorCause
Contact Email is requiredclientEmail missing or empty
Contact Email must be a valid email addressInvalid email format
Business Name is requiredbusinessName missing or empty
Contact Name is requiredcontactName missing or empty
Policy / Reference # is requiredpolicyNumber missing or empty
At least one Line of Assesment is requiredlines array is empty
General Liability (GL) requires Property (PR) to also be selectedGL without PR
Photo uploads are not available for Fleet (FL) or Contractors Liability (CL) only ordersphotosRequired: true with only FL/CL
Photo uploads require at least the Smart planphotosRequired: true without upgradeSmart or upgradeIntelligent
Third-Party Notification Email must be a valid email addressthirdPartyEmail is not a valid email format
Unrecognized key(s) in object: '...'Request body included unsupported fields

Other 400 errors:

Error CodeMessage
SMART_REQUIRED_FOR_INTELLIGENTSmart plan required before Intelligent upgrade (MGA/Agency only)
INVALID_IDEMPOTENCY_KEYIdempotency-Key must be a string of 128 characters or fewer

401 — Authentication Error

{ "message": "API key required", "error": "MISSING_API_KEY" }
{ "message": "Invalid or inactive API key", "error": "INVALID_API_KEY" }

403 — Forbidden

Error CodeMessage
SUBSCRIPTION_REQUIREDAPI access requires an active partner subscription with current status. Check your billing status on the Partner Account page.
MONTHLY_QUOTA_EXCEEDEDMonthly order quota reached for this API key
BUDGET_LIMIT_REACHEDOrder would exceed the account’s monthly budget

404 — Not Found

{ "message": "Order not found", "error": "ORDER_NOT_FOUND" }
{ "message": "Error: Company not found", "error": "COMPANY_NOT_FOUND" }

409 — Conflict

Client already exists:

{
  "message": "A client account already exists for jane@acmecorp.com. Please contact support if you need to re-order.",
  "error": "EXISTING_RISK_PROFILE"
}

Re-orders for existing clients are not supported via the API in v1. To re-order, use the Partner Dashboard or contact support@smarterrisk.com.

Concurrent order:

{
  "message": "Your account is currently processing an order. Please try again in a moment.",
  "error": "ORDER_PROCESSING_IN_PROGRESS"
}

Another order for your account is being processed — either via the API or the Partner Dashboard. Retry with exponential backoff starting at 5 seconds (e.g. 5s, 10s, 20s).

429 — Rate Limited

{
  "message": "Rate limit exceeded. Please slow down.",
  "error": "RATE_LIMIT_EXCEEDED",
  "retryAfter": 12
}

Wait the number of seconds indicated by retryAfter (also sent as the Retry-After header) before retrying.

500 — Server Error

{
  "message": "Error: There was a problem processing the order",
  "error": "ORDER_PROCESSING_ERROR"
}
Error CodeRetryableNotes
CLIENT_SETUP_FAILEDYesNo payment was taken. Retry may succeed, but if partial account creation occurred, the retry may return 409 EXISTING_RISK_PROFILE — contact support in that case.
ORDER_PROCESSING_ERRORMaybeGeneric unexpected failure. Contact support if it persists after one retry.

503 — Dependency Unavailable

{
  "message": "Pricing service unavailable — please try again",
  "error": "PRICING_UNAVAILABLE"
}

SmarterRisk cannot retrieve live pricing. Retry after 10–30 seconds. Contact support if it persists.


Integration Recommendations

SettingRecommendation
Request timeout30 seconds for POST /api/v1/order-intake, 10 seconds for GET /api/v1/orders/:orderId
Retry strategyRetry on 429, 500 CLIENT_SETUP_FAILED, 503. Do not retry 202, 409, or other 500 errors.
BackoffExponential backoff starting at 5 seconds, max 3 retries
IdempotencyAlways send an Idempotency-Key on POST requests to protect against network retries
Unknown fieldsIgnore unknown fields in responses — new fields may be added without a version bump

Code Examples

cURL

curl -X POST https://app.smarterrisk.com/api/v1/order-intake \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "clientEmail": "jane@acmecorp.com",
    "businessName": "Acme Corp",
    "contactName": "Jane Smith",
    "lines": ["GL", "PR"],
    "policyNumber": "POL-12345",
    "numLocations": 1
  }'

JavaScript (Node.js)

const response = await fetch('https://app.smarterrisk.com/api/v1/order-intake', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${process.env.SMARTERRISK_API_KEY}`,
    'Idempotency-Key': crypto.randomUUID(),
  },
  body: JSON.stringify({
    clientEmail: 'jane@acmecorp.com',
    businessName: 'Acme Corp',
    contactName: 'Jane Smith',
    lines: ['GL', 'PR'],
    policyNumber: 'POL-12345',
    numLocations: 1,
  }),
});

const data = await response.json();

if (response.status === 201) {
  console.log('Order created:', data.orderId, data.plan, data.orderCost);
} else if (response.status === 202) {
  // Order accepted but a downstream step failed — do not retry
  console.warn('Order degraded:', data.orderId, data.status);
  console.warn('Contact support with orderId:', data.orderId);
  if (data.invoiceID) console.warn('Invoice:', data.invoiceID);
} else {
  console.error('Order failed:', response.status, data.error, data.message);
  if (data.errors) {
    data.errors.forEach(e => console.error(`  ${e.label}: ${e.message}`));
  }
}

Python

import os
import uuid
import requests

api_key = os.environ["SMARTERRISK_API_KEY"]
base_url = "https://app.smarterrisk.com"

response = requests.post(
    f"{base_url}/api/v1/order-intake",
    headers={
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "clientEmail": "jane@acmecorp.com",
        "businessName": "Acme Corp",
        "contactName": "Jane Smith",
        "lines": ["GL", "PR"],
        "policyNumber": "POL-12345",
        "numLocations": 1,
    },
    timeout=30,
)

data = response.json()

if response.status_code == 201:
    print(f"Order created: {data['orderId']} ({data['plan']}) — {data['orderCost']}")
elif response.status_code == 202:
    # Order accepted but degraded — do not retry
    print(f"Order degraded: {data['orderId']} ({data['status']})")
    print(f"Contact support with orderId: {data['orderId']}")
else:
    print(f"Order failed ({response.status_code}): {data['message']}")

PHP

$apiKey  = getenv('SMARTERRISK_API_KEY');
$baseUrl = 'https://app.smarterrisk.com';

$ch = curl_init("$baseUrl/api/v1/order-intake");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_TIMEOUT        => 30,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        "Authorization: Bearer $apiKey",
        'Idempotency-Key: ' . bin2hex(random_bytes(16)),
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'clientEmail'  => 'jane@acmecorp.com',
        'businessName' => 'Acme Corp',
        'contactName'  => 'Jane Smith',
        'lines'        => ['GL', 'PR'],
        'policyNumber' => 'POL-12345',
        'numLocations' => 1,
    ]),
]);

$body   = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

$data = json_decode($body, true);

if ($status === 201) {
    echo "Order created: {$data['orderId']} ({$data['plan']}) — {$data['orderCost']}";
} elseif ($status === 202) {
    // Order accepted but degraded — do not retry
    echo "Order degraded: {$data['orderId']} ({$data['status']}) — contact support";
} else {
    echo "Order failed ($status): {$data['message']}";
}

Troubleshooting

ProblemLikely CauseFix
401 MISSING_API_KEYNo Authorization headerAdd Authorization: Bearer YOUR_KEY header
401 INVALID_API_KEYKey revoked, expired, or wrong environmentCheck the key is active in your API Integration dashboard
403 SUBSCRIPTION_REQUIREDSubscription lapsed or not activeCheck your billing status on the Partner Account page — subscription must be current
400 VALIDATION_ERROR with “Unrecognized key(s)”Extra fields in request bodyRemove any fields not listed in the schema
400 with “GL requires PR”Sent GL without PRAdd "PR" to your lines array
409 EXISTING_RISK_PROFILEClient email already has an accountUse the Partner Dashboard to manage existing clients
409 ORDER_PROCESSING_IN_PROGRESSAnother order is being processedWait 5–10 seconds and retry
403 MONTHLY_QUOTA_EXCEEDEDHit your key’s monthly limitContact your admin to increase the quota
403 BUDGET_LIMIT_REACHEDOrder would exceed monthly budgetContact your admin to increase the budget
503 PRICING_UNAVAILABLETemporary pricing service issueRetry after 10–30 seconds
Order created but client didn’t get emailNormal processing delayAllow up to 5 minutes. Check your Partner Dashboard for order status.

Current V1 Limitations

  • No validation-only or quote/estimate endpoint
  • No webhook callbacks
  • No API endpoints for reports, scores, recommendations, forms, or assessment results
  • No bulk order endpoint
  • No re-order support for existing clients

Use the Partner Dashboard for downstream risk artifacts until a future API version introduces retrieval endpoints.


Support

For API access, key management, or integration questions contact support@smarterrisk.com.