ROYAL AiAPI
checking…

Version 1 · api.royalai.ai

ROVER, inside your product.

The AI for everything in a home loan, with the same guardrails as every ROYAL Ai surface. One key, three calls, live in an afternoon. Test keys are free and never touch the model.

Try it nowRead the reference

  • Same engine. Partners and borrowers get one ROVER, one guard, one set of rails.
  • Server to server. A key never belongs in a browser or an app bundle.
  • Nothing you send is kept beyond the hand-off. Questions are never written to disk.
ROVER
Ask ROVERlive, right here, the answer your key gets
ROVER answers in his own words, streamed sentence by sentence.

The same call with your key
POST /v1/ask
Authorization: Bearer rai_live_…
{"question":"How does a HELOC work?","context":{"world":"equity","surface":"borrower"}}

Every lender's overlays, before you submit

DU and LPA approve to the agency rule. A wholesale lender can add a stricter rule of its own, an overlay, and decline the file late. One call tests a file against the agency books and every lender in the brain. Every rule comes back with its section, its page and its date. This page runs on the public sandbox key, which sees a sample of three lenders; your live key sees every lender in the brain.

A purchase of a primary home, one unit, a 30-year term, qualifying on assets. Change a number and test it again: at 62 the answer changes.

The same call with your key
POST /v1/overlays/test

What you can build with it

Nine things partners ship first. Every one runs through the same guard a borrower meets on royalai.app.

  1. An answer bar in your appAny question about a home loan, answered in ROVER's voice, with a rail under it that says what it is.
  2. Payment and amortization estimatesYour rate, our arithmetic. Every estimate carries its disclosure.
  3. A consented hand-offWhen someone says "have Royal call me," one call files the lead with the exact words they agreed to.
  4. Status, pushed to your CRMSigned webhooks the moment a lead moves: contacted, application started, with the lender, closed.
  5. ROVER Agent for your agent portalThe partner persona for real-estate professionals: contract mechanics, customary costs, where to go next.
  6. Meet people where they areSixteen worlds, from "just dreaming" to "retiring at home." Tell ROVER the world and the voice follows.
  7. Streaming, token by tokenAsk for Server-Sent Events and paint the answer as it arrives, exactly as Royal's own sites do.
  8. A free sandboxBuild the whole integration on a test key. Same envelope, same validation, no model, no bill.
  9. Compliance by constructionNo rates from us, no approvals in a status, sensitive data refused on sight, every request audited.

Quickstart

1
Get a key. Write to bryan@royalai.ai with your company, your use case and the audience you serve. You get a rai_test_ key the same day. Or start right now with the public sandbox key in the console below.
2
Ask ROVER.
curl https://api.royalai.ai/v1/ask \
  -H "Authorization: Bearer $ROYAL_KEY" \
  -H "Content-Type: application/json" \
  -d '{"question":"How does a HELOC work?","context":{"world":"equity","surface":"borrower"}}'

The answer is {id, object:"answer", mode, text, meta, done}. Show text, then done.followup under it. When done.handoff is true the person needs a licensed human, and done.navigate names the world the question belongs in.

3
Go live. Check GET /v1/health once before go-live and confirm durable:true, then swap the test key for a rai_live_ key. Nothing else changes: same routes, same envelope, same validation.

Try it

A real request to this API from your browser. The public sandbox key is filled in; paste your own to see your data, and every lender in the brain rather than the sandbox's sample of three. Sandbox answers are placeholders in the real envelope.

Ready.
{ }

Reference

Generated from the live OpenAPI 3.1 specification, so it cannot drift from the server. Base URL https://api.royalai.ai. Every error is {"error":{"code","message","requestId"}}.

Loading the specification…

Webhooks

Register an https endpoint and ROYAL Ai posts a signed event when a lead is created or its status changes. Delivery is at least once, from this address, within ten seconds of the event.

The event

{
  "id": "evt_1c0b7d2e4a513f9a",
  "object": "event",
  "type": "lead.status_changed",
  "livemode": true,
  "createdAt": "2026-11-03T15:04:05.000Z",
  "data": {
    "lead": { "id": "lead_3f9a1c0b7d2e4a51", "status": "contacted", "…": "…" },
    "previousStatus": "received"
  }
}

The headers

X-Royal-Eventthe event type
X-Royal-Deliverythe event id, the same on every retry
X-Royal-Signaturet=<unix>,v1=<hex>, HMAC-SHA256 of "<t>.<raw body>" with your endpoint secret. Two v1 values for 24 hours after a rotation.

Retries

Anything but a 2xx is retried: now, then +10 s, +1 min, +10 min, +1 h, +6 h, then marked dead. Read GET /v1/webhooks/{id}/deliveries to see every attempt. Redirects are never followed. Deduplicate on the event id.

Verify every delivery

import crypto from 'node:crypto';

export function verify(secret, header, rawBody, toleranceSec = 300) {
  const parts = header.split(',').map((p) => p.trim());
  const t = Number((parts.find((p) => p.startsWith('t=')) || '').slice(2));
  if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
  return parts.filter((p) => p.startsWith('v1=')).some((p) => {
    const sig = Buffer.from(p.slice(3), 'hex');
    return sig.length === expected.length && crypto.timingSafeEqual(sig, expected);
  });
}
// rawBody must be the exact bytes received, before any JSON parsing.

Good hygiene

  • Answer 2xx fast and do the work afterwards; ten seconds is the deadline.
  • Rotate the secret with POST /v1/webhooks/{id}/rotate; both secrets verify for a day.
  • Send yourself a ping with POST /v1/webhooks/{id}/ping before you go live.
  • Endpoints must be https on port 443 at a public host. Private names and addresses are refused at registration and again at every delivery.

Errors and limits

HTTPcodemeaning
400invalid_request invalid_json unknown_field too_long consent_required invalid_statusFix the request. The message says which field.
401unauthorizedMissing, revoked, expired or malformed key.
403forbiddenThe key lacks the scope the route needs.
404not_found not_hereNot yours, does not exist, or the wrong host.
409idempotency_mismatchSame Idempotency-Key, different body.
413too_long payload_too_large2000 characters for a question, 32 KB for a body.
422sensitive_dataAn SSN, card, account, routing or ID number, or a date of birth, was in the request. Nothing was stored.
429rate_limited too_many_in_flightWait Retry-After seconds.
503storage_not_durable storage_unavailable unavailableNothing was recorded; retry with the same Idempotency-Key. Go-live checklist: GET /v1/health reads durable:true.

Limits

  • Each key has a per-minute limit. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset.
  • Each key may hold a few answers in flight at once (maxInFlight on GET /v1/me). Over it, 429 too_many_in_flight.
  • Up to 10 webhook endpoints per mode. Lists return at most 100 records, newest first.
  • Send Idempotency-Key on every lead; retries are then free and safe.
  • Quote X-Request-Id when you write to us.

Test mode

A rai_test_ key answers from the sandbox: real validation, real envelope, placeholder words, no model. Sandbox leads and webhooks live in their own space and are cleared when the service restarts. A test key can never see live data, even for the same partner.

Security and compliance

Keys are hashed, never stored.

The secret is shown once. We keep its SHA-256 only, so no file, backup or env var holds a working key. Revocation takes effect within seconds.

Sensitive data is refused, not flagged.

A lead needs a name, a way to reach the person and their consent. SSNs, cards, account and routing numbers, ID numbers and dates of birth are refused on sight (422), in any field, and nothing is stored.

Questions are never written down.

The engine keeps a metadata ledger: counts, rule ids, timing. Never a question, never an answer, never an IP. The API audit log is the same: who, which route, what outcome, hash-chained line by line.

One guard for everyone.

/v1/ask is the same handler as the public ask bar: the same sentence gate, the same escalation to a human, the same rails. No rates, no approvals, no "you'd qualify."

The lender decides.

Lead statuses are received, contacted, application_started, with_lender, closed, withdrawn. There is no "approved" in this API, because a human underwriter signs every decision.

Webhooks cannot be turned inward.

Endpoints must be public https on 443. Names are resolved at every delivery, private addresses are refused, the connection is pinned, redirects are never followed, secrets are sealed at rest.

ROVER is an AI. Answers are information, not advice or an offer to lend. A licensed lender makes every credit decision. Partners agree not to pay or be paid for referrals in any way the law forbids, and to show the consent words exactly as the person saw them.

Status

Checking GET /v1/health…