{"openapi":"3.1.0","info":{"title":"ROYAL Ai API","version":"1.0.0","summary":"ROVER, the AI for everything in a home loan, inside your own product.","description":"Same guardrails as every ROYAL Ai surface: the same engine answers partners and borrowers alike. Server-to-server only. Never put a key in a browser or an app bundle. Test keys (rai_test_…) are free, never reach the live model, and keep their data in a separate sandbox. Every error is `{\"error\":{\"code\",\"message\",\"requestId\"}}` and every response carries X-Request-Id.","termsOfService":"https://royalai.ai","contact":{"name":"ROYAL Ai","url":"https://royalai.ai"}},"servers":[{"url":"https://api.royalai.ai"}],"security":[{"bearer":[]}],"tags":[{"name":"ROVER","description":"Ask the engine."},{"name":"Lender brain","description":"Agency rules and wholesale lender overlays, each one cited and dated. Test a file against all of them."},{"name":"Calculators","description":"Arithmetic on the numbers you send. No rates from us."},{"name":"Leads","description":"Consented hand-offs into Royal."},{"name":"Applications","description":"The full mortgage application (the 1003): ROVER asks, every answer is saved, the borrower signs on Royal's secure page, and the loan officer runs the soft pull and ROYAL Ai underwriting."},{"name":"Webhooks","description":"Signed event deliveries to your endpoint."},{"name":"Public","description":"No key needed."}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Authorization: Bearer rai_live_… or rai_test_…"}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}},"Lead":{"type":"object","properties":{"id":{"type":"string","example":"lead_3f9a1c0b7d2e4a51"},"object":{"type":"string","const":"lead"},"mode":{"type":"string","enum":["live","test"]},"status":{"type":"string","enum":["received","contacted","application_started","with_lender","closed","withdrawn"]},"purpose":{"type":["string","null"]},"contact":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}}},"state":{"type":["string","null"],"example":"FL"},"notes":{"type":["string","null"]},"source":{"type":["string","null"]},"externalId":{"type":["string","null"]},"consent":{"type":"object","properties":{"given":{"type":"boolean"},"text":{"type":"string"},"at":{"type":["string","null"]},"method":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"LeadIn":{"type":"object","required":["contact","consent"],"additionalProperties":false,"properties":{"contact":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":120},"email":{"type":"string","format":"email","maxLength":200},"phone":{"type":"string","maxLength":32,"description":"10 to 15 digits; punctuation is removed."}},"description":"name is required, plus at least one of email or phone."},"consent":{"type":"object","required":["given","text"],"properties":{"given":{"type":"boolean","const":true},"text":{"type":"string","maxLength":2000,"description":"The exact words the person agreed to."},"at":{"type":"string","format":"date-time"},"method":{"type":"string","maxLength":40,"example":"web-form"}}},"purpose":{"type":"string","maxLength":32,"description":"A world key from GET /v1/worlds (firsttime, equity, refi, …)."},"state":{"type":"string","pattern":"^[A-Z]{2}$"},"notes":{"type":"string","maxLength":2000},"source":{"type":"string","maxLength":80,"example":"rate page on acme.com"},"externalId":{"type":"string","maxLength":128,"description":"Your own record id."}}},"Application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"ApplicationIn":{"type":"object","required":["borrower","consent"],"additionalProperties":false,"description":"Start an application. Never the identity: no SSN, birth date or account number in any field (422). The borrower types those on the secure page Royal sends when the application is complete.","properties":{"borrower":{"type":"object","required":["firstName"],"additionalProperties":false,"properties":{"firstName":{"type":"string","maxLength":60},"email":{"type":"string","format":"email"},"phone":{"type":"string","description":"10 to 15 digits"}},"description":"A first name and an email or phone: where the secure link goes."},"consent":{"type":"object","required":["given","text"],"additionalProperties":false,"properties":{"given":{"const":true},"text":{"type":"string","maxLength":2000,"description":"The exact words the person agreed to (to be contacted about this application)."}}},"language":{"enum":["en","es"],"default":"en","description":"The language of the questions, the secure page and the next steps."},"answers":{"type":"object","description":"Optional: answers already given, keyed by question key (the same format as POST /v1/applications/{id}/answers)."},"notes":{"type":"string","maxLength":2000}}},"Question":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}},"Progress":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."}}},"Webhook":{"type":"object","properties":{"id":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"mode":{"type":"string","enum":["live","test"]},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["lead.created","lead.status_changed","application.completed","application.ready_for_soft_pull","application.status_changed","ping"]}},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active"]},"createdAt":{"type":"string","format":"date-time"},"rotatedAt":{"type":["string","null"],"format":"date-time"},"previousSecretExpiresAt":{"type":["string","null"],"format":"date-time"}}},"WebhookWithSecret":{"allOf":[{"type":"object","properties":{"id":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"mode":{"type":"string","enum":["live","test"]},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["lead.created","lead.status_changed","application.completed","application.ready_for_soft_pull","application.status_changed","ping"]}},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active"]},"createdAt":{"type":"string","format":"date-time"},"rotatedAt":{"type":["string","null"],"format":"date-time"},"previousSecretExpiresAt":{"type":["string","null"],"format":"date-time"}}},{"type":"object","properties":{"secret":{"type":"string","description":"Shown once. whsec_…"}}}]},"Delivery":{"type":"object","properties":{"id":{"type":"string"},"eventId":{"type":"string"},"type":{"type":"string"},"attempt":{"type":"integer"},"status":{"type":"integer","description":"HTTP status from your endpoint, 0 when the connection failed."},"ok":{"type":"boolean"},"error":{"type":["string","null"]},"at":{"type":"string","format":"date-time"}}},"Event":{"type":"object","description":"The JSON body of every webhook delivery.","properties":{"id":{"type":"string","example":"evt_1c0b7d2e4a513f9a"},"object":{"type":"string","const":"event"},"type":{"type":"string","enum":["lead.created","lead.status_changed","application.completed","application.ready_for_soft_pull","application.status_changed","ping"]},"livemode":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"lead":{"type":"object","properties":{"id":{"type":"string","example":"lead_3f9a1c0b7d2e4a51"},"object":{"type":"string","const":"lead"},"mode":{"type":"string","enum":["live","test"]},"status":{"type":"string","enum":["received","contacted","application_started","with_lender","closed","withdrawn"]},"purpose":{"type":["string","null"]},"contact":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}}},"state":{"type":["string","null"],"example":"FL"},"notes":{"type":["string","null"]},"source":{"type":["string","null"]},"externalId":{"type":["string","null"]},"consent":{"type":"object","properties":{"given":{"type":"boolean"},"text":{"type":"string"},"at":{"type":["string","null"]},"method":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"previousStatus":{"type":"string"}}}}},"Answer":{"type":"object","required":["id","object","mode","text","meta","done"],"properties":{"id":{"type":"string"},"object":{"type":"string","const":"answer"},"mode":{"type":"string","enum":["live","test"]},"text":{"type":"string"},"meta":{"type":"object","properties":{"world":{"type":["string","null"]},"surface":{"type":["string","null"]},"stage":{"type":"string"},"escalate":{"type":"boolean"},"npiDetected":{"type":"boolean"},"nonEnglish":{"type":"boolean"},"roverAgent":{"type":"boolean"},"agentFocus":{"type":["string","null"]},"outOfScope":{"type":"boolean"},"sandbox":{"type":"boolean","description":"Present and true on a test-key answer."}}},"done":{"type":"object","properties":{"followup":{"type":["string","null"],"description":"The rail to show under the answer."},"handoff":{"type":"boolean","description":"True when the answer routes the person to a licensed human."},"reason":{"type":["string","null"],"enum":["guard","refusal","truncated","engine","sandbox",null]},"rule":{"type":"string","description":"Opaque rule token on a guard trip."},"navigate":{"type":["string","null"],"description":"The world the question belongs in, when the engine can tell."},"calculator":{"type":["string","null"],"enum":["purchase","equity",null]}}}}},"AskIn":{"type":"object","required":["question"],"properties":{"question":{"type":"string","minLength":1,"maxLength":2000},"history":{"type":"array","maxItems":20,"items":{"type":"object","required":["role","text"],"properties":{"role":{"type":"string","enum":["user","assistant"]},"text":{"type":"string","maxLength":2000}}},"description":"Earlier turns, oldest first. The engine replays at most the newest 8 turns and redacts sensitive data in them."},"context":{"type":"object","properties":{"world":{"type":"string","description":"Where the person is in the process. Keys from GET /v1/worlds."},"surface":{"type":"string","description":"Who is asking. Keys from GET /v1/worlds."},"tool":{"type":"string","description":"An optional slug naming the tool the question came from."},"asksSoFar":{"type":"integer","minimum":0},"worldsVisited":{"type":"array","items":{"type":"string"},"maxItems":16},"fast":{"type":"boolean","description":"FAST MODE (2026-11-04): no jokes, no pleasantries, half the words, with the same laws, doors and disclosures. Off unless sent. A person can also throw the switch in their own words (\"fast mode\", \"normal mode\"); the meta frame reports fast (the verdict for the turn) and fastSwitch (\"on\", \"off\" or null) so a client can remember the choice."}}},"agent":{"type":"boolean","description":"ROVER Agent, the partner persona for real-estate professionals. Needs the agent scope."},"stream":{"type":"boolean","default":false,"description":"true for Server-Sent Events (meta, delta, done)."}}},"CalcIn":{"type":"object","required":["loanAmount","annualRatePercent","termYears"],"properties":{"loanAmount":{"type":"number","minimum":1,"maximum":100000000},"annualRatePercent":{"type":"number","minimum":0,"maximum":30,"description":"You supply the rate. ROYAL Ai never quotes one."},"termYears":{"type":"number","minimum":1,"maximum":40},"monthlyTaxes":{"type":"number","minimum":0},"monthlyInsurance":{"type":"number","minimum":0},"monthlyHoa":{"type":"number","minimum":0},"monthlyMi":{"type":"number","minimum":0}},"description":"Every field must be a JSON number. Strings, null and booleans are refused."},"AmortIn":{"type":"object","required":["loanAmount","annualRatePercent","termYears"],"properties":{"loanAmount":{"type":"number","minimum":1,"maximum":100000000},"annualRatePercent":{"type":"number","minimum":0,"maximum":30},"termYears":{"type":"number","minimum":1,"maximum":40},"extraMonthlyPrincipal":{"type":"number","minimum":0}}},"OverlayTestIn":{"type":"object","required":["file"],"additionalProperties":false,"properties":{"file":{"type":"object","additionalProperties":false,"description":"The facts of a loan, never of a person. There is no field for a name, an address or an account number, and an unknown field is refused. Send at least one fact the brain can test: creditScore, assetIncome, loanAmount, or aus \"manual\". The more of the other facts you send (aus, ltv, propertyType, amortization), the fewer lenders come back needing a fact.","properties":{"program":{"type":"string","enum":["conventional","fha","va","usda"],"default":"conventional"},"aus":{"type":"string","enum":["DU","LPA","manual"],"description":"The engine the file ran through. DU follows Fannie Mae's book, LPA follows Freddie Mac's. Leave it out to see both."},"loanPurpose":{"type":"string","enum":["purchase","rate_term_refinance","cash_out_refinance"],"description":"rate_term_refinance is Fannie Mae's limited cash-out and Freddie Mac's no cash-out refinance."},"occupancy":{"type":"string","enum":["primary","second_home","investment"]},"units":{"type":"integer","minimum":1,"maximum":4},"propertyType":{"type":"string","enum":["single_family","condo","pud","townhome","manufactured","co_op","multi_unit"]},"state":{"type":"string","pattern":"^[A-Z]{2}$"},"loanAmount":{"type":"number","minimum":1},"ltv":{"type":"number","description":"Percent. The test uses the higher of ltv and cltv."},"cltv":{"type":"number"},"creditScore":{"type":"integer","minimum":300,"maximum":850},"dti":{"type":"number","minimum":0,"maximum":100},"amortization":{"type":"string","enum":["fixed","arm"]},"termMonths":{"type":"integer","minimum":60,"maximum":480,"default":360},"assetIncome":{"type":"object","required":["assets"],"additionalProperties":false,"description":"Assets used as qualifying income (\"asset depletion\"). Needs ltv, loanPurpose, occupancy and units as well.","properties":{"assets":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","required":["type","amount","ownerAge"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["retirement_401k","retirement_ira","retirement_sep","retirement_keogh","lump_sum_retirement","severance","checking","savings","brokerage","business_sale","crypto"]},"amount":{"type":"number","exclusiveMinimum":0,"description":"The balance, in dollars."},"ownerAge":{"type":"integer","minimum":18,"maximum":120,"description":"The age at closing of the borrower who owns the asset."},"penaltyPercent":{"type":"number","minimum":0,"maximum":100,"default":0,"description":"The penalty a full withdrawal would carry today. 0 when none applies."},"drawnAsIncome":{"type":"boolean","default":false,"description":"True when the borrower already draws income from this asset."},"fromEmploymentAsset":{"type":"boolean","default":false,"description":"For checking, savings and brokerage: true when the balance came from a severance package, a lump-sum retirement distribution or a retirement account."}}}},"fundsToClose":{"type":"number","minimum":0,"default":0,"description":"Money from these assets used for the down payment, closing costs and required reserves."}}}}},"lenders":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"string"},"description":"Lender ids from GET /v1/lenders. Leave it out to test every lender in the brain."}}},"OverlayFile":{"type":"object","additionalProperties":false,"description":"The facts of a loan, never of a person. There is no field for a name, an address or an account number, and an unknown field is refused. Send at least one fact the brain can test: creditScore, assetIncome, loanAmount, or aus \"manual\". The more of the other facts you send (aus, ltv, propertyType, amortization), the fewer lenders come back needing a fact.","properties":{"program":{"type":"string","enum":["conventional","fha","va","usda"],"default":"conventional"},"aus":{"type":"string","enum":["DU","LPA","manual"],"description":"The engine the file ran through. DU follows Fannie Mae's book, LPA follows Freddie Mac's. Leave it out to see both."},"loanPurpose":{"type":"string","enum":["purchase","rate_term_refinance","cash_out_refinance"],"description":"rate_term_refinance is Fannie Mae's limited cash-out and Freddie Mac's no cash-out refinance."},"occupancy":{"type":"string","enum":["primary","second_home","investment"]},"units":{"type":"integer","minimum":1,"maximum":4},"propertyType":{"type":"string","enum":["single_family","condo","pud","townhome","manufactured","co_op","multi_unit"]},"state":{"type":"string","pattern":"^[A-Z]{2}$"},"loanAmount":{"type":"number","minimum":1},"ltv":{"type":"number","description":"Percent. The test uses the higher of ltv and cltv."},"cltv":{"type":"number"},"creditScore":{"type":"integer","minimum":300,"maximum":850},"dti":{"type":"number","minimum":0,"maximum":100},"amortization":{"type":"string","enum":["fixed","arm"]},"termMonths":{"type":"integer","minimum":60,"maximum":480,"default":360},"assetIncome":{"type":"object","required":["assets"],"additionalProperties":false,"description":"Assets used as qualifying income (\"asset depletion\"). Needs ltv, loanPurpose, occupancy and units as well.","properties":{"assets":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","required":["type","amount","ownerAge"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["retirement_401k","retirement_ira","retirement_sep","retirement_keogh","lump_sum_retirement","severance","checking","savings","brokerage","business_sale","crypto"]},"amount":{"type":"number","exclusiveMinimum":0,"description":"The balance, in dollars."},"ownerAge":{"type":"integer","minimum":18,"maximum":120,"description":"The age at closing of the borrower who owns the asset."},"penaltyPercent":{"type":"number","minimum":0,"maximum":100,"default":0,"description":"The penalty a full withdrawal would carry today. 0 when none applies."},"drawnAsIncome":{"type":"boolean","default":false,"description":"True when the borrower already draws income from this asset."},"fromEmploymentAsset":{"type":"boolean","default":false,"description":"For checking, savings and brokerage: true when the balance came from a severance package, a lump-sum retirement distribution or a retirement account."}}}},"fundsToClose":{"type":"number","minimum":0,"default":0,"description":"Money from these assets used for the down payment, closing costs and required reserves."}}}}},"OverlayTest":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"overlay_test"},"mode":{"type":"string","enum":["live","test"]},"asOf":{"type":"string","format":"date-time"},"staleAfterDays":{"type":"integer","example":30},"file":{"type":"object","additionalProperties":false,"description":"The facts of a loan, never of a person. There is no field for a name, an address or an account number, and an unknown field is refused. Send at least one fact the brain can test: creditScore, assetIncome, loanAmount, or aus \"manual\". The more of the other facts you send (aus, ltv, propertyType, amortization), the fewer lenders come back needing a fact.","properties":{"program":{"type":"string","enum":["conventional","fha","va","usda"],"default":"conventional"},"aus":{"type":"string","enum":["DU","LPA","manual"],"description":"The engine the file ran through. DU follows Fannie Mae's book, LPA follows Freddie Mac's. Leave it out to see both."},"loanPurpose":{"type":"string","enum":["purchase","rate_term_refinance","cash_out_refinance"],"description":"rate_term_refinance is Fannie Mae's limited cash-out and Freddie Mac's no cash-out refinance."},"occupancy":{"type":"string","enum":["primary","second_home","investment"]},"units":{"type":"integer","minimum":1,"maximum":4},"propertyType":{"type":"string","enum":["single_family","condo","pud","townhome","manufactured","co_op","multi_unit"]},"state":{"type":"string","pattern":"^[A-Z]{2}$"},"loanAmount":{"type":"number","minimum":1},"ltv":{"type":"number","description":"Percent. The test uses the higher of ltv and cltv."},"cltv":{"type":"number"},"creditScore":{"type":"integer","minimum":300,"maximum":850},"dti":{"type":"number","minimum":0,"maximum":100},"amortization":{"type":"string","enum":["fixed","arm"]},"termMonths":{"type":"integer","minimum":60,"maximum":480,"default":360},"assetIncome":{"type":"object","required":["assets"],"additionalProperties":false,"description":"Assets used as qualifying income (\"asset depletion\"). Needs ltv, loanPurpose, occupancy and units as well.","properties":{"assets":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","required":["type","amount","ownerAge"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["retirement_401k","retirement_ira","retirement_sep","retirement_keogh","lump_sum_retirement","severance","checking","savings","brokerage","business_sale","crypto"]},"amount":{"type":"number","exclusiveMinimum":0,"description":"The balance, in dollars."},"ownerAge":{"type":"integer","minimum":18,"maximum":120,"description":"The age at closing of the borrower who owns the asset."},"penaltyPercent":{"type":"number","minimum":0,"maximum":100,"default":0,"description":"The penalty a full withdrawal would carry today. 0 when none applies."},"drawnAsIncome":{"type":"boolean","default":false,"description":"True when the borrower already draws income from this asset."},"fromEmploymentAsset":{"type":"boolean","default":false,"description":"For checking, savings and brokerage: true when the balance came from a severance package, a lump-sum retirement distribution or a retirement account."}}}},"fundsToClose":{"type":"number","minimum":0,"default":0,"description":"Money from these assets used for the down payment, closing costs and required reserves."}}}}},"topics":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"}}},"description":"The topics this file raises that the brain holds a rule on."},"agencies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"freddie-mac"},"name":{"type":"string"},"aus":{"type":"string","enum":["DU","LPA"]},"verdict":{"type":"string","enum":["meets","fails","needs_facts","not_covered"]},"topics":{"type":"array","items":{"type":"object","properties":{"topic":{"type":"string"},"label":{"type":"string"},"verdict":{"type":"string","enum":["meets","fails","needs_facts","not_covered"]},"needs":{"type":"array","items":{"type":"string"}},"checks":{"type":"array","items":{"type":"object","properties":{"rule":{"type":"string"},"topic":{"type":"string"},"ok":{"type":["boolean","null"],"description":"true: the file meets the rule. false: it does not. null: a fact is missing (see needs)."},"info":{"type":"boolean","description":"Present and true on a rule that states a fact and asks nothing of the file."},"needs":{"type":"array","items":{"type":"string"}},"excludedAssets":{"type":"array","items":{"type":"integer"},"description":"Indexes of the assets this rule left out."},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"},"stale":{"type":"boolean"}}}},"assets":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"type":{"type":"string"},"amount":{"type":"number"},"ownerAge":{"type":"integer"},"counted":{"type":"boolean"},"excludedBy":{"type":"array","items":{"type":"string"}}}}},"income":{"type":"object","description":"The qualifying income this book gives the assets, with the arithmetic.","properties":{"monthly":{"type":"number"},"eligibleAssets":{"type":"number"},"lessPenalty":{"type":"number"},"lessFundsToClose":{"type":"number"},"netAssets":{"type":"number"},"divisor":{"type":"number"},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"},"stale":{"type":"boolean"}}},"alsoRequires":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"},"stale":{"type":"boolean"}}},"description":"Conditions the file must also meet that this test does not check."}}}}}}},"lenders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"mega-capital-funding"},"name":{"type":"string"},"verdict":{"type":"string","enum":["clear","conflict","not_verified"],"description":"clear: Royal has verified this lender's whole position on every topic the file raises, and nothing stands against the file. conflict: a rule does, and it is cited. not_verified: Royal has not verified this lender's whole position on a topic the file raises."},"via":{"type":"array","items":{"type":"string","enum":["DU","LPA"]},"description":"On a clear verdict: the path or paths that are clear."},"paths":{"type":"array","items":{"type":"object","properties":{"aus":{"type":"string","enum":["DU","LPA"]},"agency":{"type":"string"},"verdict":{"type":"string","enum":["clear","conflict","not_verified"]},"reasons":{"type":"array","items":{"allOf":[{"type":"object","properties":{"rule":{"type":"string"},"topic":{"type":"string"},"ok":{"type":["boolean","null"],"description":"true: the file meets the rule. false: it does not. null: a fact is missing (see needs)."},"info":{"type":"boolean","description":"Present and true on a rule that states a fact and asks nothing of the file."},"needs":{"type":"array","items":{"type":"string"}},"excludedAssets":{"type":"array","items":{"type":"integer"},"description":"Indexes of the assets this rule left out."},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"},"stale":{"type":"boolean"}}},{"type":"object","properties":{"kind":{"type":"string","enum":["overlay","agency_rule"],"description":"overlay: the lender's own, stricter rule. agency_rule: the agency rule itself, which no lender can waive."},"appliesBook":{"type":"string"},"because":{"type":"object","description":"The lender policy that brings another agency's book to bear, with its citation."}}}]}},"notVerified":{"type":"array","items":{"type":"object","properties":{"topic":{"type":"string"},"label":{"type":"string"},"lastVerified":{"type":["string","null"],"format":"date"},"partly":{"type":"boolean","description":"True when Royal has read some of this lender's rules on the topic but not its whole position. Passing those rules is not a clear."},"says":{"type":"string"}}}},"alsoRequires":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"topic":{"type":"string"},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"}}},"description":"Cited conditions of the lender's that this test does not check, such as seasoning or documentation."},"needs":{"type":"array","items":{"type":"string"}},"qualifyingMonthlyIncome":{"type":"number","description":"On a clear path with asset income: the lower of the incomes the applicable books allow."}}}}}},"description":"clear first, then conflict, then not_verified."},"summary":{"type":"object","properties":{"lenders":{"type":"integer"},"clear":{"type":"integer"},"conflict":{"type":"integer"},"notVerified":{"type":"integer"}}},"sample":{"type":"boolean","description":"Present and true on a test-key answer: the sample lenders were tested, not the whole brain."},"note":{"type":"string","description":"With sample: one line saying so. A live key tests every lender."},"warnings":{"type":"array","items":{"type":"string"}},"disclosure":{"type":"string"}}},"Guideline":{"type":"object","properties":{"id":{"type":"string","example":"fnma.asset-income.ltv"},"object":{"type":"string","const":"guideline"},"kind":{"type":"string","enum":["rule","calculation","policy","note"]},"publisher":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["agency","lender"]}}},"program":{"type":"string","enum":["conventional","fha","va","usda"]},"topic":{"type":"string","example":"asset_depletion"},"says":{"type":"string","description":"ROYAL Ai's plain-English summary. Never the guide's own text."},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date","description":"The date Royal last read this rule in its source."},"stale":{"type":"boolean","description":"True when verified is older than the window (30 days)."}}},"Cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"Lender":{"type":"object","properties":{"id":{"type":"string","example":"pennymac-tpo"},"object":{"type":"string","const":"lender"},"name":{"type":"string"},"channel":{"type":"string","example":"wholesale"},"website":{"type":["string","null"],"format":"uri"},"topics":{"type":"object","description":"What the brain holds on this lender, topic by topic. A topic that is absent has not been verified.","additionalProperties":{"type":"object","properties":{"status":{"type":"string","enum":["verified","stale"]},"verified":{"type":"string","format":"date"},"rules":{"type":"integer"}}}}}},"GuidelineChange":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"guideline_change"},"date":{"type":"string","format":"date","description":"The day the brain recorded the change."},"type":{"type":"string","enum":["added","changed","retired","upcoming"]},"publisher":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"}}},"topic":{"type":"string"},"rule":{"type":["string","null"]},"effective":{"type":["string","null"],"format":"date","description":"When the rule takes or took effect at its publisher."},"summary":{"type":"string"}}}},"headers":{"X-Request-Id":{"schema":{"type":"string"},"description":"Quote it when you write to us."},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}}},"paths":{"/v1/health":{"get":{"tags":["Public"],"summary":"Liveness","security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"api":{"type":"string"},"version":{"type":"string"},"host":{"type":"string"},"durable":{"type":"boolean","description":"True when live writes are open on this host. Check it once before go-live."},"time":{"type":"string","format":"date-time"}}}}}}}}},"/v1/openapi.json":{"get":{"tags":["Public"],"summary":"This specification","security":[],"responses":{"200":{"description":"OpenAPI 3.1 document"}}}},"/v1/worlds":{"get":{"tags":["Public"],"summary":"The vocabulary: worlds (where the person is) and surfaces (who is asking)","security":[],"description":"Use these keys in context.world, context.surface and a lead's purpose. An unknown key is ignored, never an error.","responses":{"200":{"description":"Worlds and surfaces","content":{"application/json":{"schema":{"type":"object","properties":{"worlds":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"stage":{"type":"string"},"label":{"type":"string"}}}},"surfaces":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"}}}}}}}}}}}},"/v1/me":{"get":{"tags":["Public"],"summary":"The key you are using","responses":{"200":{"description":"Key details, never the secret or its hash","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"object","properties":{"id":{"type":"string"},"partnerId":{"type":"string"},"name":{"type":"string"},"audience":{"type":"string"},"mode":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"rateLimitPerMin":{"type":"integer"},"maxInFlight":{"type":"integer"},"createdAt":{"type":"string"},"expiresAt":{"type":["string","null"]}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/ask":{"post":{"tags":["ROVER"],"summary":"Ask ROVER","x-scopes":["ask"],"description":"One JSON answer by default. Send `\"stream\": true` or `Accept: text/event-stream` for Server-Sent Events: `meta` (one frame, first), `delta` (text pieces), `done` (one frame, last). A test key answers from the sandbox with the same envelope. Each key may hold a limited number of answers in flight (429 too_many_in_flight).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["question"],"properties":{"question":{"type":"string","minLength":1,"maxLength":2000},"history":{"type":"array","maxItems":20,"items":{"type":"object","required":["role","text"],"properties":{"role":{"type":"string","enum":["user","assistant"]},"text":{"type":"string","maxLength":2000}}},"description":"Earlier turns, oldest first. The engine replays at most the newest 8 turns and redacts sensitive data in them."},"context":{"type":"object","properties":{"world":{"type":"string","description":"Where the person is in the process. Keys from GET /v1/worlds."},"surface":{"type":"string","description":"Who is asking. Keys from GET /v1/worlds."},"tool":{"type":"string","description":"An optional slug naming the tool the question came from."},"asksSoFar":{"type":"integer","minimum":0},"worldsVisited":{"type":"array","items":{"type":"string"},"maxItems":16},"fast":{"type":"boolean","description":"FAST MODE (2026-11-04): no jokes, no pleasantries, half the words, with the same laws, doors and disclosures. Off unless sent. A person can also throw the switch in their own words (\"fast mode\", \"normal mode\"); the meta frame reports fast (the verdict for the turn) and fastSwitch (\"on\", \"off\" or null) so a client can remember the choice."}}},"agent":{"type":"boolean","description":"ROVER Agent, the partner persona for real-estate professionals. Needs the agent scope."},"stream":{"type":"boolean","default":false,"description":"true for Server-Sent Events (meta, delta, done)."}}}}}},"responses":{"200":{"description":"The answer","content":{"application/json":{"schema":{"type":"object","required":["id","object","mode","text","meta","done"],"properties":{"id":{"type":"string"},"object":{"type":"string","const":"answer"},"mode":{"type":"string","enum":["live","test"]},"text":{"type":"string"},"meta":{"type":"object","properties":{"world":{"type":["string","null"]},"surface":{"type":["string","null"]},"stage":{"type":"string"},"escalate":{"type":"boolean"},"npiDetected":{"type":"boolean"},"nonEnglish":{"type":"boolean"},"roverAgent":{"type":"boolean"},"agentFocus":{"type":["string","null"]},"outOfScope":{"type":"boolean"},"sandbox":{"type":"boolean","description":"Present and true on a test-key answer."}}},"done":{"type":"object","properties":{"followup":{"type":["string","null"],"description":"The rail to show under the answer."},"handoff":{"type":"boolean","description":"True when the answer routes the person to a licensed human."},"reason":{"type":["string","null"],"enum":["guard","refusal","truncated","engine","sandbox",null]},"rule":{"type":"string","description":"Opaque rule token on a guard trip."},"navigate":{"type":["string","null"],"description":"The world the question belongs in, when the engine can tell."},"calculator":{"type":["string","null"],"enum":["purchase","equity",null]}}}}}},"text/event-stream":{"schema":{"type":"string","description":"event: meta | delta | done, each with a JSON data line"}}}},"400":{"description":"question missing, or history malformed","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the ask (and agent, for agent:true) scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"413":{"description":"question over 2000 characters","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"agent:true asked on a host without ROVER Agent configured","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/calculators/payment":{"post":{"tags":["Calculators"],"summary":"Monthly payment estimate","x-scopes":["calculators"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["loanAmount","annualRatePercent","termYears"],"properties":{"loanAmount":{"type":"number","minimum":1,"maximum":100000000},"annualRatePercent":{"type":"number","minimum":0,"maximum":30,"description":"You supply the rate. ROYAL Ai never quotes one."},"termYears":{"type":"number","minimum":1,"maximum":40},"monthlyTaxes":{"type":"number","minimum":0},"monthlyInsurance":{"type":"number","minimum":0},"monthlyHoa":{"type":"number","minimum":0},"monthlyMi":{"type":"number","minimum":0}},"description":"Every field must be a JSON number. Strings, null and booleans are refused."}}}},"responses":{"200":{"description":"Estimate with the disclosure line","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"estimate"},"monthlyPrincipalAndInterest":{"type":"number"},"monthlyEscrow":{"type":"number"},"monthlyTotal":{"type":"number"},"totalInterest":{"type":"number"},"disclosure":{"type":"string"}}}}}},"400":{"description":"An input is missing, not a JSON number, or out of range","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the calculators scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/calculators/amortization":{"post":{"tags":["Calculators"],"summary":"Year-by-year amortization schedule","x-scopes":["calculators"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["loanAmount","annualRatePercent","termYears"],"properties":{"loanAmount":{"type":"number","minimum":1,"maximum":100000000},"annualRatePercent":{"type":"number","minimum":0,"maximum":30},"termYears":{"type":"number","minimum":1,"maximum":40},"extraMonthlyPrincipal":{"type":"number","minimum":0}}}}}},"responses":{"200":{"description":"Schedule and totals","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"estimate"},"monthsToPayoff":{"type":"integer"},"totalInterest":{"type":"number"},"interestSavedByExtraPayments":{"type":"number"},"schedule":{"type":"array","items":{"type":"object","properties":{"year":{"type":"integer"},"principalPaid":{"type":"number"},"interestPaid":{"type":"number"},"endingBalance":{"type":"number"}}}},"disclosure":{"type":"string"}}}}}},"400":{"description":"An input is missing, not a JSON number, or out of range","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the calculators scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/overlays/test":{"post":{"tags":["Lender brain"],"summary":"Test a loan file against every lender's published rules","x-scopes":["overlays"],"description":"Send the facts of a loan. The answer shows what each agency book says about the file (Fannie Mae for DU, Freddie Mac for LPA), then every lender in the brain: `clear` (Royal has verified the lender's whole position and nothing stands against the file), `conflict` (a rule does, with its citation) or `not_verified` (Royal has not verified that lender's whole position on a topic the file raises). When the agency's own rule fails, every lender on that path is in conflict: no lender can waive an agency rule. An overlay is a lender's own rule that is stricter than the agency rule, so a file DU or LPA accepted can still be declined; this call reads the overlay first. No model is used: the same file always gets the same answer. It is a rule check, never a credit decision. The lender's underwriter decides. Some sources are shown only to keys with the overlays-private scope. A test key tests a sample of the lenders and says so (`sample: true`); a live key tests every lender in the brain.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["file"],"additionalProperties":false,"properties":{"file":{"type":"object","additionalProperties":false,"description":"The facts of a loan, never of a person. There is no field for a name, an address or an account number, and an unknown field is refused. Send at least one fact the brain can test: creditScore, assetIncome, loanAmount, or aus \"manual\". The more of the other facts you send (aus, ltv, propertyType, amortization), the fewer lenders come back needing a fact.","properties":{"program":{"type":"string","enum":["conventional","fha","va","usda"],"default":"conventional"},"aus":{"type":"string","enum":["DU","LPA","manual"],"description":"The engine the file ran through. DU follows Fannie Mae's book, LPA follows Freddie Mac's. Leave it out to see both."},"loanPurpose":{"type":"string","enum":["purchase","rate_term_refinance","cash_out_refinance"],"description":"rate_term_refinance is Fannie Mae's limited cash-out and Freddie Mac's no cash-out refinance."},"occupancy":{"type":"string","enum":["primary","second_home","investment"]},"units":{"type":"integer","minimum":1,"maximum":4},"propertyType":{"type":"string","enum":["single_family","condo","pud","townhome","manufactured","co_op","multi_unit"]},"state":{"type":"string","pattern":"^[A-Z]{2}$"},"loanAmount":{"type":"number","minimum":1},"ltv":{"type":"number","description":"Percent. The test uses the higher of ltv and cltv."},"cltv":{"type":"number"},"creditScore":{"type":"integer","minimum":300,"maximum":850},"dti":{"type":"number","minimum":0,"maximum":100},"amortization":{"type":"string","enum":["fixed","arm"]},"termMonths":{"type":"integer","minimum":60,"maximum":480,"default":360},"assetIncome":{"type":"object","required":["assets"],"additionalProperties":false,"description":"Assets used as qualifying income (\"asset depletion\"). Needs ltv, loanPurpose, occupancy and units as well.","properties":{"assets":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","required":["type","amount","ownerAge"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["retirement_401k","retirement_ira","retirement_sep","retirement_keogh","lump_sum_retirement","severance","checking","savings","brokerage","business_sale","crypto"]},"amount":{"type":"number","exclusiveMinimum":0,"description":"The balance, in dollars."},"ownerAge":{"type":"integer","minimum":18,"maximum":120,"description":"The age at closing of the borrower who owns the asset."},"penaltyPercent":{"type":"number","minimum":0,"maximum":100,"default":0,"description":"The penalty a full withdrawal would carry today. 0 when none applies."},"drawnAsIncome":{"type":"boolean","default":false,"description":"True when the borrower already draws income from this asset."},"fromEmploymentAsset":{"type":"boolean","default":false,"description":"For checking, savings and brokerage: true when the balance came from a severance package, a lump-sum retirement distribution or a retirement account."}}}},"fundsToClose":{"type":"number","minimum":0,"default":0,"description":"Money from these assets used for the down payment, closing costs and required reserves."}}}}},"lenders":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"string"},"description":"Lender ids from GET /v1/lenders. Leave it out to test every lender in the brain."}}}}}},"responses":{"200":{"description":"What the agencies and each lender's published rules say about the file","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"overlay_test"},"mode":{"type":"string","enum":["live","test"]},"asOf":{"type":"string","format":"date-time"},"staleAfterDays":{"type":"integer","example":30},"file":{"type":"object","additionalProperties":false,"description":"The facts of a loan, never of a person. There is no field for a name, an address or an account number, and an unknown field is refused. Send at least one fact the brain can test: creditScore, assetIncome, loanAmount, or aus \"manual\". The more of the other facts you send (aus, ltv, propertyType, amortization), the fewer lenders come back needing a fact.","properties":{"program":{"type":"string","enum":["conventional","fha","va","usda"],"default":"conventional"},"aus":{"type":"string","enum":["DU","LPA","manual"],"description":"The engine the file ran through. DU follows Fannie Mae's book, LPA follows Freddie Mac's. Leave it out to see both."},"loanPurpose":{"type":"string","enum":["purchase","rate_term_refinance","cash_out_refinance"],"description":"rate_term_refinance is Fannie Mae's limited cash-out and Freddie Mac's no cash-out refinance."},"occupancy":{"type":"string","enum":["primary","second_home","investment"]},"units":{"type":"integer","minimum":1,"maximum":4},"propertyType":{"type":"string","enum":["single_family","condo","pud","townhome","manufactured","co_op","multi_unit"]},"state":{"type":"string","pattern":"^[A-Z]{2}$"},"loanAmount":{"type":"number","minimum":1},"ltv":{"type":"number","description":"Percent. The test uses the higher of ltv and cltv."},"cltv":{"type":"number"},"creditScore":{"type":"integer","minimum":300,"maximum":850},"dti":{"type":"number","minimum":0,"maximum":100},"amortization":{"type":"string","enum":["fixed","arm"]},"termMonths":{"type":"integer","minimum":60,"maximum":480,"default":360},"assetIncome":{"type":"object","required":["assets"],"additionalProperties":false,"description":"Assets used as qualifying income (\"asset depletion\"). Needs ltv, loanPurpose, occupancy and units as well.","properties":{"assets":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","required":["type","amount","ownerAge"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["retirement_401k","retirement_ira","retirement_sep","retirement_keogh","lump_sum_retirement","severance","checking","savings","brokerage","business_sale","crypto"]},"amount":{"type":"number","exclusiveMinimum":0,"description":"The balance, in dollars."},"ownerAge":{"type":"integer","minimum":18,"maximum":120,"description":"The age at closing of the borrower who owns the asset."},"penaltyPercent":{"type":"number","minimum":0,"maximum":100,"default":0,"description":"The penalty a full withdrawal would carry today. 0 when none applies."},"drawnAsIncome":{"type":"boolean","default":false,"description":"True when the borrower already draws income from this asset."},"fromEmploymentAsset":{"type":"boolean","default":false,"description":"For checking, savings and brokerage: true when the balance came from a severance package, a lump-sum retirement distribution or a retirement account."}}}},"fundsToClose":{"type":"number","minimum":0,"default":0,"description":"Money from these assets used for the down payment, closing costs and required reserves."}}}}},"topics":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"}}},"description":"The topics this file raises that the brain holds a rule on."},"agencies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"freddie-mac"},"name":{"type":"string"},"aus":{"type":"string","enum":["DU","LPA"]},"verdict":{"type":"string","enum":["meets","fails","needs_facts","not_covered"]},"topics":{"type":"array","items":{"type":"object","properties":{"topic":{"type":"string"},"label":{"type":"string"},"verdict":{"type":"string","enum":["meets","fails","needs_facts","not_covered"]},"needs":{"type":"array","items":{"type":"string"}},"checks":{"type":"array","items":{"type":"object","properties":{"rule":{"type":"string"},"topic":{"type":"string"},"ok":{"type":["boolean","null"],"description":"true: the file meets the rule. false: it does not. null: a fact is missing (see needs)."},"info":{"type":"boolean","description":"Present and true on a rule that states a fact and asks nothing of the file."},"needs":{"type":"array","items":{"type":"string"}},"excludedAssets":{"type":"array","items":{"type":"integer"},"description":"Indexes of the assets this rule left out."},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"},"stale":{"type":"boolean"}}}},"assets":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"type":{"type":"string"},"amount":{"type":"number"},"ownerAge":{"type":"integer"},"counted":{"type":"boolean"},"excludedBy":{"type":"array","items":{"type":"string"}}}}},"income":{"type":"object","description":"The qualifying income this book gives the assets, with the arithmetic.","properties":{"monthly":{"type":"number"},"eligibleAssets":{"type":"number"},"lessPenalty":{"type":"number"},"lessFundsToClose":{"type":"number"},"netAssets":{"type":"number"},"divisor":{"type":"number"},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"},"stale":{"type":"boolean"}}},"alsoRequires":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"},"stale":{"type":"boolean"}}},"description":"Conditions the file must also meet that this test does not check."}}}}}}},"lenders":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"mega-capital-funding"},"name":{"type":"string"},"verdict":{"type":"string","enum":["clear","conflict","not_verified"],"description":"clear: Royal has verified this lender's whole position on every topic the file raises, and nothing stands against the file. conflict: a rule does, and it is cited. not_verified: Royal has not verified this lender's whole position on a topic the file raises."},"via":{"type":"array","items":{"type":"string","enum":["DU","LPA"]},"description":"On a clear verdict: the path or paths that are clear."},"paths":{"type":"array","items":{"type":"object","properties":{"aus":{"type":"string","enum":["DU","LPA"]},"agency":{"type":"string"},"verdict":{"type":"string","enum":["clear","conflict","not_verified"]},"reasons":{"type":"array","items":{"allOf":[{"type":"object","properties":{"rule":{"type":"string"},"topic":{"type":"string"},"ok":{"type":["boolean","null"],"description":"true: the file meets the rule. false: it does not. null: a fact is missing (see needs)."},"info":{"type":"boolean","description":"Present and true on a rule that states a fact and asks nothing of the file."},"needs":{"type":"array","items":{"type":"string"}},"excludedAssets":{"type":"array","items":{"type":"integer"},"description":"Indexes of the assets this rule left out."},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"},"stale":{"type":"boolean"}}},{"type":"object","properties":{"kind":{"type":"string","enum":["overlay","agency_rule"],"description":"overlay: the lender's own, stricter rule. agency_rule: the agency rule itself, which no lender can waive."},"appliesBook":{"type":"string"},"because":{"type":"object","description":"The lender policy that brings another agency's book to bear, with its citation."}}}]}},"notVerified":{"type":"array","items":{"type":"object","properties":{"topic":{"type":"string"},"label":{"type":"string"},"lastVerified":{"type":["string","null"],"format":"date"},"partly":{"type":"boolean","description":"True when Royal has read some of this lender's rules on the topic but not its whole position. Passing those rules is not a clear."},"says":{"type":"string"}}}},"alsoRequires":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"topic":{"type":"string"},"says":{"type":"string"},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date"}}},"description":"Cited conditions of the lender's that this test does not check, such as seasoning or documentation."},"needs":{"type":"array","items":{"type":"string"}},"qualifyingMonthlyIncome":{"type":"number","description":"On a clear path with asset income: the lower of the incomes the applicable books allow."}}}}}},"description":"clear first, then conflict, then not_verified."},"summary":{"type":"object","properties":{"lenders":{"type":"integer"},"clear":{"type":"integer"},"conflict":{"type":"integer"},"notVerified":{"type":"integer"}}},"sample":{"type":"boolean","description":"Present and true on a test-key answer: the sample lenders were tested, not the whole brain."},"note":{"type":"string","description":"With sample: one line saying so. A live key tests every lender."},"warnings":{"type":"array","items":{"type":"string"}},"disclosure":{"type":"string"}}}}}},"400":{"description":"invalid_request, unknown_field or nothing_to_test","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the overlays scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"brain_unavailable: the rule library could not be read on this host, and nothing was guessed","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/lenders":{"get":{"tags":["Lender brain"],"summary":"The wholesale lenders in the brain, and what is verified on each","x-scopes":["overlays"],"description":"A test key lists the sample lenders only; a live key lists every lender. The same applies to /v1/lenders/{id}, /v1/guidelines and /v1/guidelines/changes.","responses":{"200":{"description":"Lenders by name, and the agency books","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"pennymac-tpo"},"object":{"type":"string","const":"lender"},"name":{"type":"string"},"channel":{"type":"string","example":"wholesale"},"website":{"type":["string","null"],"format":"uri"},"topics":{"type":"object","description":"What the brain holds on this lender, topic by topic. A topic that is absent has not been verified.","additionalProperties":{"type":"object","properties":{"status":{"type":"string","enum":["verified","stale"]},"verified":{"type":"string","format":"date"},"rules":{"type":"integer"}}}}}}},"agencies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"aus":{"type":"string"}}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the overlays scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"brain_unavailable","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/lenders/{id}":{"get":{"tags":["Lender brain"],"summary":"One lender and every rule the brain holds on it","x-scopes":["overlays"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"pennymac-tpo"},"description":"Lender id"}],"responses":{"200":{"description":"The lender and its guidelines","content":{"application/json":{"schema":{"type":"object","properties":{"lender":{"type":"object","properties":{"id":{"type":"string","example":"pennymac-tpo"},"object":{"type":"string","const":"lender"},"name":{"type":"string"},"channel":{"type":"string","example":"wholesale"},"website":{"type":["string","null"],"format":"uri"},"topics":{"type":"object","description":"What the brain holds on this lender, topic by topic. A topic that is absent has not been verified.","additionalProperties":{"type":"object","properties":{"status":{"type":"string","enum":["verified","stale"]},"verified":{"type":"string","format":"date"},"rules":{"type":"integer"}}}}}},"guidelines":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"fnma.asset-income.ltv"},"object":{"type":"string","const":"guideline"},"kind":{"type":"string","enum":["rule","calculation","policy","note"]},"publisher":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["agency","lender"]}}},"program":{"type":"string","enum":["conventional","fha","va","usda"]},"topic":{"type":"string","example":"asset_depletion"},"says":{"type":"string","description":"ROYAL Ai's plain-English summary. Never the guide's own text."},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date","description":"The date Royal last read this rule in its source."},"stale":{"type":"boolean","description":"True when verified is older than the window (30 days)."}}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the overlays scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"No such lender","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"brain_unavailable","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/guidelines":{"get":{"tags":["Lender brain"],"summary":"Search the rules: agencies and lenders, each with its citation","x-scopes":["overlays"],"parameters":[{"name":"q","in":"query","schema":{"type":"string","maxLength":200},"description":"Words to find. Every word must appear on the rule."},{"name":"publisher","in":"query","schema":{"type":"string"},"description":"An agency or lender id, for example fannie-mae."},{"name":"topic","in":"query","schema":{"type":"string","enum":["asset_depletion","credit_score","underwriting","loan_amount","property","dti","ltv","state"]}},{"name":"program","in":"query","schema":{"type":"string","enum":["conventional","fha","va","usda"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}}],"responses":{"200":{"description":"Matching rules","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"fnma.asset-income.ltv"},"object":{"type":"string","const":"guideline"},"kind":{"type":"string","enum":["rule","calculation","policy","note"]},"publisher":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["agency","lender"]}}},"program":{"type":"string","enum":["conventional","fha","va","usda"]},"topic":{"type":"string","example":"asset_depletion"},"says":{"type":"string","description":"ROYAL Ai's plain-English summary. Never the guide's own text."},"cite":{"type":"object","description":"Where a rule comes from. Every rule in the brain has one.","properties":{"document":{"type":["string","null"],"example":"Fannie Mae Selling Guide"},"edition":{"type":["string","null"],"example":"Published October 7, 2026"},"section":{"type":"string","example":"B3-3.4-06"},"title":{"type":["string","null"],"example":"Employment Related Assets as Qualifying Income"},"page":{"type":["string","null"],"example":"342"},"effective":{"type":"string","format":"date","description":"The date the section took effect."},"url":{"type":["string","null"],"format":"uri"},"retrieved":{"type":["string","null"],"format":"date","description":"The date Royal obtained the document."},"access":{"type":["string","null"],"enum":["public",null],"description":"Some sources are shown only to keys with the overlays-private scope."}}},"verified":{"type":"string","format":"date","description":"The date Royal last read this rule in its source."},"stale":{"type":"boolean","description":"True when verified is older than the window (30 days)."}}}},"topics":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"}}}}}}}}},"400":{"description":"A filter is not valid","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the overlays scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"brain_unavailable","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/guidelines/changes":{"get":{"tags":["Lender brain"],"summary":"The change feed: rules added, changed, retired or coming","x-scopes":["overlays"],"parameters":[{"name":"since","in":"query","schema":{"type":"string","format":"date"},"description":"Only changes recorded on or after this day (YYYY-MM-DD)."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":100}}],"responses":{"200":{"description":"Newest first","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"guideline_change"},"date":{"type":"string","format":"date","description":"The day the brain recorded the change."},"type":{"type":"string","enum":["added","changed","retired","upcoming"]},"publisher":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"}}},"topic":{"type":"string"},"rule":{"type":["string","null"]},"effective":{"type":["string","null"],"format":"date","description":"When the rule takes or took effect at its publisher."},"summary":{"type":"string"}}}}}}}}},"400":{"description":"since is not a date","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the overlays scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"brain_unavailable","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/leads":{"post":{"tags":["Leads"],"summary":"Hand a consented lead to ROYAL Ai","x-scopes":["leads"],"description":"Never send SSNs, card, routing or account numbers, dates of birth or ID numbers, in any field: the request is refused (422) and nothing is stored. Unknown fields are refused (400 unknown_field). Send `Idempotency-Key` to make retries safe: the same key with the same body returns the original lead (200); with a different body it is refused (409).","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["contact","consent"],"additionalProperties":false,"properties":{"contact":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":120},"email":{"type":"string","format":"email","maxLength":200},"phone":{"type":"string","maxLength":32,"description":"10 to 15 digits; punctuation is removed."}},"description":"name is required, plus at least one of email or phone."},"consent":{"type":"object","required":["given","text"],"properties":{"given":{"type":"boolean","const":true},"text":{"type":"string","maxLength":2000,"description":"The exact words the person agreed to."},"at":{"type":"string","format":"date-time"},"method":{"type":"string","maxLength":40,"example":"web-form"}}},"purpose":{"type":"string","maxLength":32,"description":"A world key from GET /v1/worlds (firsttime, equity, refi, …)."},"state":{"type":"string","pattern":"^[A-Z]{2}$"},"notes":{"type":"string","maxLength":2000},"source":{"type":"string","maxLength":80,"example":"rate page on acme.com"},"externalId":{"type":"string","maxLength":128,"description":"Your own record id."}}}}}},"responses":{"200":{"description":"Idempotent replay of an earlier request","content":{"application/json":{"schema":{"type":"object","properties":{"lead":{"type":"object","properties":{"id":{"type":"string","example":"lead_3f9a1c0b7d2e4a51"},"object":{"type":"string","const":"lead"},"mode":{"type":"string","enum":["live","test"]},"status":{"type":"string","enum":["received","contacted","application_started","with_lender","closed","withdrawn"]},"purpose":{"type":["string","null"]},"contact":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}}},"state":{"type":["string","null"],"example":"FL"},"notes":{"type":["string","null"]},"source":{"type":["string","null"]},"externalId":{"type":["string","null"]},"consent":{"type":"object","properties":{"given":{"type":"boolean"},"text":{"type":"string"},"at":{"type":["string","null"]},"method":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"idempotent":{"const":true}}}}}},"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"lead":{"type":"object","properties":{"id":{"type":"string","example":"lead_3f9a1c0b7d2e4a51"},"object":{"type":"string","const":"lead"},"mode":{"type":"string","enum":["live","test"]},"status":{"type":"string","enum":["received","contacted","application_started","with_lender","closed","withdrawn"]},"purpose":{"type":["string","null"]},"contact":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}}},"state":{"type":["string","null"],"example":"FL"},"notes":{"type":["string","null"]},"source":{"type":["string","null"]},"externalId":{"type":["string","null"]},"consent":{"type":"object","properties":{"given":{"type":"boolean"},"text":{"type":"string"},"at":{"type":["string","null"]},"method":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"invalid_request, consent_required, unknown_field or too_long","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the leads scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"409":{"description":"idempotency_mismatch","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"422":{"description":"sensitive_data: the kinds found, and the first field","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"Live writes are not open on this host yet; nothing was recorded, retry with the same request. Go-live checklist: GET /v1/health reads durable:true. Test mode is unaffected","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}},"get":{"tags":["Leads"],"summary":"Your most recent leads","x-scopes":["leads"],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["received","contacted","application_started","with_lender","closed","withdrawn"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}}],"responses":{"200":{"description":"Newest first","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"lead_3f9a1c0b7d2e4a51"},"object":{"type":"string","const":"lead"},"mode":{"type":"string","enum":["live","test"]},"status":{"type":"string","enum":["received","contacted","application_started","with_lender","closed","withdrawn"]},"purpose":{"type":["string","null"]},"contact":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}}},"state":{"type":["string","null"],"example":"FL"},"notes":{"type":["string","null"]},"source":{"type":["string","null"]},"externalId":{"type":["string","null"]},"consent":{"type":"object","properties":{"given":{"type":"boolean"},"text":{"type":"string"},"at":{"type":["string","null"]},"method":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"mode":{"type":"string"}}}}}},"400":{"description":"Bad status filter","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the leads scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/leads/{id}":{"get":{"tags":["Leads"],"summary":"One lead and its status","x-scopes":["leads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"lead_3f9a1c0b7d2e4a51"},"description":"Lead id"}],"responses":{"200":{"description":"Lead","content":{"application/json":{"schema":{"type":"object","properties":{"lead":{"type":"object","properties":{"id":{"type":"string","example":"lead_3f9a1c0b7d2e4a51"},"object":{"type":"string","const":"lead"},"mode":{"type":"string","enum":["live","test"]},"status":{"type":"string","enum":["received","contacted","application_started","with_lender","closed","withdrawn"]},"purpose":{"type":["string","null"]},"contact":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}}},"state":{"type":["string","null"],"example":"FL"},"notes":{"type":["string","null"]},"source":{"type":["string","null"]},"externalId":{"type":["string","null"]},"consent":{"type":"object","properties":{"given":{"type":"boolean"},"text":{"type":"string"},"at":{"type":["string","null"]},"method":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the leads scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}},"patch":{"tags":["Leads"],"summary":"Withdraw a lead (the person asked to stop)","x-scopes":["leads"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"lead_3f9a1c0b7d2e4a51"},"description":"Lead id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"const":"withdrawn"}}}}}},"responses":{"200":{"description":"Lead","content":{"application/json":{"schema":{"type":"object","properties":{"lead":{"type":"object","properties":{"id":{"type":"string","example":"lead_3f9a1c0b7d2e4a51"},"object":{"type":"string","const":"lead"},"mode":{"type":"string","enum":["live","test"]},"status":{"type":"string","enum":["received","contacted","application_started","with_lender","closed","withdrawn"]},"purpose":{"type":["string","null"]},"contact":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]}}},"state":{"type":["string","null"],"example":"FL"},"notes":{"type":["string","null"]},"source":{"type":["string","null"]},"externalId":{"type":["string","null"]},"consent":{"type":"object","properties":{"given":{"type":"boolean"},"text":{"type":"string"},"at":{"type":["string","null"]},"method":{"type":["string","null"]}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"A partner may only set withdrawn","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the leads scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"Live writes are not open on this host yet; nothing was recorded, retry with the same request. Go-live checklist: GET /v1/health reads durable:true. Test mode is unaffected","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/applications":{"post":{"tags":["Applications"],"summary":"Start a mortgage application (the 1003)","x-scopes":["applications"],"description":"Returns the application, an access key (shown once; required on every later call for an application started with a public key) and the first questions, in ROVER's words. Answer with POST /v1/applications/{id}/answers. When the application is complete, every borrower gets a single-use secure link (15 minutes) for the code, the SSN, the birth date and the credit authorization. A test key gets the links and codes back for demos and accepts only made-up SSNs that start with 000. A live key never gets a link back (it goes to the borrower) and is refused (503 not_live_yet) until Royal opens live applications.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["borrower","consent"],"additionalProperties":false,"description":"Start an application. Never the identity: no SSN, birth date or account number in any field (422). The borrower types those on the secure page Royal sends when the application is complete.","properties":{"borrower":{"type":"object","required":["firstName"],"additionalProperties":false,"properties":{"firstName":{"type":"string","maxLength":60},"email":{"type":"string","format":"email"},"phone":{"type":"string","description":"10 to 15 digits"}},"description":"A first name and an email or phone: where the secure link goes."},"consent":{"type":"object","required":["given","text"],"additionalProperties":false,"properties":{"given":{"const":true},"text":{"type":"string","maxLength":2000,"description":"The exact words the person agreed to (to be contacted about this application)."}}},"language":{"enum":["en","es"],"default":"en","description":"The language of the questions, the secure page and the next steps."},"answers":{"type":"object","description":"Optional: answers already given, keyed by question key (the same format as POST /v1/applications/{id}/answers)."},"notes":{"type":"string","maxLength":2000}}}}}},"responses":{"201":{"description":"Started","content":{"application/json":{"schema":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."},"accessKey":{"type":"string","description":"Shown once. Send it as X-Application-Key."}}}}}},"400":{"description":"invalid_request, consent_required or unknown_field","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"422":{"description":"sensitive_data: an SSN, birth date or account number was sent","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"not_live_yet or storage_unavailable","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}},"get":{"tags":["Applications"],"summary":"Your applications, newest first (not for public keys)","x-scopes":["applications"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/applications/{id}":{"get":{"tags":["Applications"],"summary":"Where an application stands, and the next questions","x-scopes":["applications"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"description":"Application id"},{"name":"X-Application-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The access key returned when the application started. Required for applications started with a public key."},{"name":"lang","in":"query","schema":{"enum":["en","es"]}}],"responses":{"200":{"description":"Progress","content":{"application/json":{"schema":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, wrong access key, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}},"patch":{"tags":["Applications"],"summary":"Withdraw an application (locked, never opened again)","x-scopes":["applications"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"description":"Application id"},{"name":"X-Application-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The access key returned when the application started. Required for applications started with a public key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"const":"withdrawn"}}}}}},"responses":{"200":{"description":"Progress","content":{"application/json":{"schema":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."}}}}}},"400":{"description":"A partner may only set withdrawn","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"Live writes are not open on this host yet; nothing was recorded, retry with the same request. Go-live checklist: GET /v1/health reads durable:true. Test mode is unaffected","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/applications/{id}/questions":{"get":{"tags":["Applications"],"summary":"The next questions to ask, and how complete the application is","x-scopes":["applications"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"description":"Application id"},{"name":"X-Application-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The access key returned when the application started. Required for applications started with a public key."},{"name":"lang","in":"query","schema":{"enum":["en","es"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":8}}],"responses":{"200":{"description":"Questions","content":{"application/json":{"schema":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}},"completeness":{"type":"object"},"status":{"type":"string"}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, wrong access key, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/applications/{id}/answers":{"post":{"tags":["Applications"],"summary":"Save answers (keyed by question key); get what was saved and the next questions","x-scopes":["applications"],"description":"Answers are applied in the order of the application, so an answer can unlock a later question in the same call. null clears an answer. Each rejection says why. The answer that completes the application issues the secure links and returns the next steps for the borrower.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"description":"Application id"},{"name":"X-Application-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The access key returned when the application started. Required for applications started with a public key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["answers"],"additionalProperties":false,"properties":{"answers":{"type":"object"}}}}}},"responses":{"200":{"description":"Progress","content":{"application/json":{"schema":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."}}}}}},"400":{"description":"invalid_request","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, wrong access key, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"409":{"description":"closed: the application takes no more answers","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"422":{"description":"sensitive_data","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"Live writes are not open on this host yet; nothing was recorded, retry with the same request. Go-live checklist: GET /v1/health reads durable:true. Test mode is unaffected","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/applications/{id}/secure-link":{"post":{"tags":["Applications"],"summary":"A fresh secure link for a borrower who has not signed yet (the old one dies)","x-scopes":["applications"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"description":"Application id"},{"name":"X-Application-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The access key returned when the application started. Required for applications started with a public key."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"borrower":{"enum":["b","c"],"default":"b"}}}}}},"responses":{"200":{"description":"Progress","content":{"application/json":{"schema":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, wrong access key, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"409":{"description":"not_now or already_signed","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"Live writes are not open on this host yet; nothing was recorded, retry with the same request. Go-live checklist: GET /v1/health reads durable:true. Test mode is unaffected","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/applications/{id}/sandbox/soft-pull":{"post":{"tags":["Applications"],"summary":"Test keys only: play the loan officer (sample soft pull and ROYAL Ai pre-review)","x-scopes":["applications"],"description":"So a demo can see the whole chain. A live soft pull is the loan officer's, on Royal's side.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"description":"Application id"},{"name":"X-Application-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The access key returned when the application started. Required for applications started with a public key."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"qualifyingRatePercent":{"type":"number"},"termMonths":{"type":"integer"},"monthlyTaxes":{"type":"number"},"monthlyInsurance":{"type":"number"},"monthlyHoa":{"type":"number"},"monthlyMi":{"type":"number"},"program":{"enum":["conventional","fha","va","usda"]},"aus":{"enum":["DU","LPA","manual"],"default":"DU"}}}}}},"responses":{"200":{"description":"Progress","content":{"application/json":{"schema":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, wrong access key, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"409":{"description":"not_ready: every borrower must sign first, or it already ran","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/applications/{id}/sandbox/underwrite":{"post":{"tags":["Applications"],"summary":"Test keys only: one tap, ROYAL Ai Underwriting (the soft pull and the pre-review run first if they have not)","x-scopes":["applications"],"description":"The loan officer's one tap, played in the sandbox. ROYAL Ai Underwriting reads the whole file: the program the situation picks, every check cited to its guide section, the lender overlays, the drafted conditions and the decision draft (ready for the pre-approval letter, or paused with the reason). Timed from the borrower's last signature. On a live file this runs from FLO or POST /v1/admin/applications/{id}/underwrite.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"description":"Application id"},{"name":"X-Application-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The access key returned when the application started. Required for applications started with a public key."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"qualifyingRatePercent":{"type":"number"},"termMonths":{"type":"integer"},"monthlyTaxes":{"type":"number"},"monthlyInsurance":{"type":"number"},"monthlyHoa":{"type":"number"},"monthlyMi":{"type":"number"},"program":{"enum":["conventional","fha","va","usda"]},"aus":{"enum":["DU","LPA","manual"],"default":"DU"}}}}}},"responses":{"200":{"description":"Progress","content":{"application/json":{"schema":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, wrong access key, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"409":{"description":"not_ready: every borrower must sign first, or it already ran","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/applications/{id}/sandbox/pre-approval":{"post":{"tags":["Applications"],"summary":"Test keys only: issue the pre-approval letter ROVER drafted (only on a file ROYAL Ai called ready)","x-scopes":["applications"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"description":"Application id"},{"name":"X-Application-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The access key returned when the application started. Required for applications started with a public key."}],"responses":{"200":{"description":"Progress","content":{"application/json":{"schema":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, wrong access key, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"409":{"description":"not_ready: underwriting first, and a paused file gets no letter","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/applications/{id}/sandbox/conditions":{"post":{"tags":["Applications"],"summary":"Test keys only: play the underwriter; ROVER PROCESSOR turns the conditions into plain words","x-scopes":["applications"],"description":"Paste a conditions sheet or AUS findings as written. Behind the counsel-gated walls: a decision word routes the sheet to a person (route \"human\") and nothing reaches the borrower; a message that would report a credit decision is held.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"description":"Application id"},{"name":"X-Application-Key","in":"header","required":false,"schema":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"The access key returned when the application started. Required for applications started with a public key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"additionalProperties":false,"properties":{"text":{"type":"string","maxLength":4000},"source":{"enum":["underwriter","du","lpa","lender"],"default":"underwriter"}}}}}},"responses":{"200":{"description":"Progress, plus the round (route, why, note)","content":{"application/json":{"schema":{"type":"object","properties":{"application":{"type":"object","properties":{"id":{"type":"string","example":"app_3f9a1c0b7d2e4a51"},"object":{"const":"application"},"mode":{"enum":["live","test"]},"status":{"enum":["interview","link_sent","identity_verified","waiting_on_co_borrower","credit_authorized","credit_received","pre_review_complete","underwritten","pre_approved","with_underwriter","withdrawn"]},"language":{"enum":["en","es"]},"borrower":{"type":"object","description":"The first name and the contact channel. Never the answers."},"completeness":{"type":"object","description":"percent, done, total and the missing 1003 checklist lines (section and label)."},"loan":{"type":"object","description":"The facts of the loan derived from the answers (purpose, occupancy, type, state, loan amount, LTV)."},"signers":{"type":"object","description":"Per borrower (b, c): link_sent, opened or signed."},"identity":{"type":"object","description":"Per borrower: onFile and the last 4 digits only. The full number never leaves the vault."},"creditAuthorization":{"type":"object"},"loanEstimate":{"type":["object","null"],"description":"Once all six TRID items are in: when the application was received and the date the Loan Estimate is due."},"credit":{"type":["object","null"],"description":"Test keys only. A live soft pull is the loan officer's to explain."},"preReview":{"type":["object","null"],"description":"Test keys only. ROYAL Ai pre-review: agencies and lender overlays, cited. Not an approval; a human underwriter decides."},"underwriting":{"type":["object","null"],"description":"ROYAL Ai Underwriting (2026-11-12). Test keys: the decision draft, the program, every check with its guide citation, the drafted conditions and the clock. Live keys: that it finished, and the words the borrower may hear. Never a credit decision."},"preApproval":{"type":["object","null"],"description":"The pre-approval letter, once the loan officer issues it. Test keys: the letter's words. Live keys: issued and expires."},"conditions":{"type":["object","null"],"description":"ROVER PROCESSOR: the latest conditions sheet in plain words for the borrower (message, items, who sends each), or route \"human\" when a decision word sent it to a person."},"timeline":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}}},"status":{"type":"object","properties":{"status":{"type":"string"},"percent":{"type":"integer"},"text":{"type":"string","description":"Where the file stands, for the borrower, in their language."}}},"accepted":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"next":{"type":"object","properties":{"intro":{"type":["string","null"]},"questions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"loan.purpose"},"ask":{"type":"string","description":"ROVER's words, in the application's language."},"type":{"type":"string"},"answerFormat":{"type":"string","description":"The JSON value to send back, in words."},"choices":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"optional":{"type":"boolean"},"section":{"type":"string","description":"The 1003 section, like 1a or 5b."},"item":{"type":"string"},"group":{"type":"string"}}}}}},"nextSteps":{"type":"object","description":"Once complete: the words to read the borrower (what happens next, the documents to get ready) and the steps."},"secureLinks":{"type":"array","items":{"type":"object"},"description":"Test keys: the link and code, so a demo can click through. Live: how each link was delivered, never the link."}}}}}},"400":{"description":"invalid_request","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the applications scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, wrong access key, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"409":{"description":"not_ready: conditions come after ROYAL Ai Underwriting","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/webhooks":{"post":{"tags":["Webhooks"],"summary":"Register an endpoint","x-scopes":["webhooks"],"description":"An https URL on port 443 at a public host. Events: lead.created, lead.status_changed (both by default), application.completed, application.ready_for_soft_pull, application.status_changed and ping. Up to 10 endpoints per mode. The signing secret is returned once. Every delivery carries `X-Royal-Signature: t=<unix>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\">`; for 24 hours after a rotation there are two v1 values.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","maxLength":2048},"events":{"type":"array","items":{"type":"string","enum":["lead.created","lead.status_changed","application.completed","application.ready_for_soft_pull","application.status_changed","ping"]}},"description":{"type":"string","maxLength":120}}}}}},"responses":{"201":{"description":"Registered; the secret is shown once","content":{"application/json":{"schema":{"type":"object","properties":{"webhook":{"allOf":[{"type":"object","properties":{"id":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"mode":{"type":"string","enum":["live","test"]},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["lead.created","lead.status_changed","application.completed","application.ready_for_soft_pull","application.status_changed","ping"]}},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active"]},"createdAt":{"type":"string","format":"date-time"},"rotatedAt":{"type":["string","null"],"format":"date-time"},"previousSecretExpiresAt":{"type":["string","null"],"format":"date-time"}}},{"type":"object","properties":{"secret":{"type":"string","description":"Shown once. whsec_…"}}}]}}}}}},"400":{"description":"Bad URL, unknown event, or too many endpoints","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the webhooks scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"Live writes are not open on this host yet; nothing was recorded, retry with the same request. Go-live checklist: GET /v1/health reads durable:true. Test mode is unaffected","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}},"get":{"tags":["Webhooks"],"summary":"Your endpoints","x-scopes":["webhooks"],"responses":{"200":{"description":"List","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"mode":{"type":"string","enum":["live","test"]},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["lead.created","lead.status_changed","application.completed","application.ready_for_soft_pull","application.status_changed","ping"]}},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active"]},"createdAt":{"type":"string","format":"date-time"},"rotatedAt":{"type":["string","null"],"format":"date-time"},"previousSecretExpiresAt":{"type":["string","null"],"format":"date-time"}}}},"mode":{"type":"string"}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the webhooks scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/webhooks/{id}":{"get":{"tags":["Webhooks"],"summary":"One endpoint","x-scopes":["webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"description":"Webhook id"}],"responses":{"200":{"description":"Webhook","content":{"application/json":{"schema":{"type":"object","properties":{"webhook":{"type":"object","properties":{"id":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"mode":{"type":"string","enum":["live","test"]},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["lead.created","lead.status_changed","application.completed","application.ready_for_soft_pull","application.status_changed","ping"]}},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active"]},"createdAt":{"type":"string","format":"date-time"},"rotatedAt":{"type":["string","null"],"format":"date-time"},"previousSecretExpiresAt":{"type":["string","null"],"format":"date-time"}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the webhooks scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}},"delete":{"tags":["Webhooks"],"summary":"Remove an endpoint (pending deliveries are cancelled)","x-scopes":["webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"description":"Webhook id"}],"responses":{"204":{"description":"Removed"},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the webhooks scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"Live writes are not open on this host yet; nothing was recorded, retry with the same request. Go-live checklist: GET /v1/health reads durable:true. Test mode is unaffected","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/webhooks/{id}/rotate":{"post":{"tags":["Webhooks"],"summary":"Rotate the signing secret (the old one verifies for 24 more hours)","x-scopes":["webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"description":"Webhook id"}],"responses":{"200":{"description":"The new secret, shown once","content":{"application/json":{"schema":{"type":"object","properties":{"webhook":{"allOf":[{"type":"object","properties":{"id":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"mode":{"type":"string","enum":["live","test"]},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["lead.created","lead.status_changed","application.completed","application.ready_for_soft_pull","application.status_changed","ping"]}},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active"]},"createdAt":{"type":"string","format":"date-time"},"rotatedAt":{"type":["string","null"],"format":"date-time"},"previousSecretExpiresAt":{"type":["string","null"],"format":"date-time"}}},{"type":"object","properties":{"secret":{"type":"string","description":"Shown once. whsec_…"}}}]}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the webhooks scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"Live writes are not open on this host yet; nothing was recorded, retry with the same request. Go-live checklist: GET /v1/health reads durable:true. Test mode is unaffected","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/webhooks/{id}/ping":{"post":{"tags":["Webhooks"],"summary":"Send a signed ping event to this endpoint","x-scopes":["webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"description":"Webhook id"}],"responses":{"202":{"description":"Queued","content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"object","properties":{"id":{"type":"string"},"type":{"const":"ping"},"createdAt":{"type":"string"}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the webhooks scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"503":{"description":"Live writes are not open on this host yet; nothing was recorded, retry with the same request. Go-live checklist: GET /v1/health reads durable:true. Test mode is unaffected","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}},"/v1/webhooks/{id}/deliveries":{"get":{"tags":["Webhooks"],"summary":"The last 50 delivery attempts at this endpoint","x-scopes":["webhooks"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"wh_7c2e4a513f9a1c0b"},"description":"Webhook id"}],"responses":{"200":{"description":"Newest first","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"eventId":{"type":"string"},"type":{"type":"string"},"attempt":{"type":"integer"},"status":{"type":"integer","description":"HTTP status from your endpoint, 0 when the connection failed."},"ok":{"type":"boolean"},"error":{"type":["string","null"]},"at":{"type":"string","format":"date-time"}}}}}}}}},"401":{"description":"Missing, revoked, expired or malformed key","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"403":{"description":"The key lacks the webhooks scope","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"404":{"description":"Not yours, or not found","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}},"429":{"description":"Over this key's per-minute limit (Retry-After and X-RateLimit-* headers are set)","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"invalid_request"},"message":{"type":"string"},"requestId":{"type":"string","example":"req_9f1c2b3a4d5e6f70"},"field":{"type":"string","description":"For sensitive_data: the first field the data was found in."}}}}}}}}}}}}}