Order lifecycle
Everything from reading the product catalog to receiving the finished report package.
1. Read the product catalog first
GET /order-types returns the products the lender may order. Read it before you
place an order, and read it again when you cache it: it tells you the report
format the product is delivered in, which appraiser certification it requires,
what it may be ordered for, and which loan types and add-ons may be attached.
curl -s https://api.appraisalhost.com/v1/order-types \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8'
{
"data": [
{
"code": "SFR-1004-36",
"name": "Single Family Residential, current report standard",
"report_format": "uad_3_6",
"appraiser_certification": "none",
"active": true,
"loan_types": [
{ "code": "conventional", "name": "Conventional" },
{ "code": "conventional_new_construction", "name": "Conventional, New Construction" },
{ "code": "va", "name": "VA" }
],
"add_ons": [
{ "code": "rent_schedule", "name": "Rent Schedule" },
{ "code": "operating_income_statement", "name": "Operating Income Statement" }
],
"loan_purposes": [],
"property_types": ["single_family", "condominium", "townhouse", "two_to_four_unit_property"]
},
{
"code": "SFR-1004-FHA",
"name": "Single Family Residential, FHA",
"report_format": "uad_3_6",
"appraiser_certification": "fha_required",
"active": true,
"loan_types": [
{ "code": "fha", "name": "FHA" }
],
"add_ons": [],
"loan_purposes": [],
"property_types": ["single_family", "condominium", "townhouse"]
},
{
"code": "DRIVEBY-2055",
"name": "Exterior Only Inspection",
"report_format": "uad_2_6",
"appraiser_certification": "none",
"active": true,
"loan_types": [],
"add_ons": [
{ "code": "rent_schedule", "name": "Rent Schedule" }
],
"loan_purposes": ["purchase"],
"property_types": []
}
],
"page": 1,
"per_page": 25,
"total": 3,
"total_pages": 1
}
Report format
report_format | What you send | What comes back |
|---|---|---|
uad_2_6 | The prior report standard. No loan type tier. Add-ons may still apply. | The report as a PDF, plus the report data as an XML file. |
uad_3_6 | The current report standard. A loan_type_code is required when the product lists loan types, and add-ons may apply. | The report as a PDF, plus the report data as a package in ZIP form. |
In both cases the invoice, the certificates and any other delivery document are separate files. The package replaces the report data file only. It never contains the invoice.
What report_data is
This is the file your system parses, so here is exactly what it is.
- On
uad_2_6,report_datais the MISMO 2.6 GSE appraisal XML, with the report PDF embedded as that standard defines. Media typeapplication/xml. It is delivered alongside the separatereport_pdfdocument. - On
uad_3_6,report_datais the UAD 3.6 delivery package, a ZIP produced by the appraiser's forms software to the GSE UAD 3.6 specification. The members of that package, and their names, are defined by that specification. Media typeapplication/zip. The package is delivered exactly as the appraiser's forms software produced it, so whether a copy of the report PDF sits inside it is that software's doing and not ours.report_pdfis always delivered as its own file as well, and that is the copy to read: take the PDF from thereport_pdfdocument rather than from inside the package.
On both standards the invoice and the certificates are always separate
documents with their own kind. Nothing is inside the package that the
specification does not put there, and the invoice never is.
Sample files for both formats are available from our integrations team: ask at
integrations@appraisalhost.com before you scope the parsing work.
Loan types and add-ons
A product may be scoped on a loan type tier, and may carry add-ons. Both come
from the product, so read them from GET /order-types rather than writing codes
into your source:
loan_type_codeis required only on a product whoseloan_typeslist is not empty, which today means products on the current report standard. Send thecode, not thename.add_on_codesare optional and must come from that product's ownadd_ons. Add-ons are not particular to one report standard: a rent schedule, an operating income statement and others apply on products of either standard, so always read the product's own list rather than assuming.loan_purposesandproperty_typeson the product say what it may be ordered for. An empty list means no restriction; a value the product does not accept is refused with422.- Some add-ons are quoted by the appraisal management company rather than priced
from a rate card. An order carrying one is placed with
fees.appraisal_feenull until the company quotes it, and you learn the price fromorder.fee_changed. - Some add-ons apply only when the property has an accessory dwelling unit.
GET /order-typeslists the add-ons that apply to a property without one by default. Passhas_adu=trueto get that list plus the add-ons that need an accessory dwelling unit, and sendproperty.has_aduon the order itself. - Codes are stable for a company. Names are display text and may be reworded.
- A product appears here only when the appraisal management company has enabled it for API ordering and given it a code. Codes are the company's own: treat them as opaque strings, because some companies use numbers.
- An unknown or inapplicable code is refused with
422and codesemantic_validation_failedrather than being guessed at, so that an order is never quietly priced on a tier you did not ask for.
active is false for a product the company has withdrawn; it cannot be
ordered. A product this lender is not entitled to order does not appear in the
list at all. The list is ordered by code, ascending.
2. Place an order
POST /orders. Always send an Idempotency-Key.
Required: order_type_code, due_date, loan.purpose, the property address
with a postal code, the property type and occupancy, and one borrower with at
least one entry in contacts.
- Borrowers. Send one borrower, and a co-borrower when there is one: the
array holds at most two people. On the borrower,
role,first_name,last_nameand at least onecontactsentry are required. On a co-borrower,role,first_nameandlast_nameare required and contacts are optional, and the contract says the same: the borrower and the co-borrower are separate schemas in it, so a generated client serialises a co-borrower with no contacts and refuses a borrower with none. A borrower with no contacts is refused with422, anddetails[].fieldisborrowers.0.contacts. Either a phone number or an email address satisfies it; send a phone number where you have one, because that is how an appraiser arranges access. - The property address. United States properties and territories only.
property.postal_codeis required. City, state and county are filled in from it when you leave them out, and the filled in values come back on the order. Where a postal code covers more than one place name we store the postal service's preferred name for it. A postal code we cannot resolve is refused with422.
Conditional requirements
The fields that are required only sometimes, in one place:
| Field | Required when | Refused with |
|---|---|---|
loan_type_code | The product's loan_types list is not empty. | 422, semantic_validation_failed |
loan.purpose_other | loan.purpose is other. | 422, semantic_validation_failed |
loan.fha_case_number | The product's appraiser_certification is fha_required or usda. | 422, semantic_validation_failed |
loan.purchase_price | loan.purpose is purchase. | 422, semantic_validation_failed |
borrowers[0].contacts | Always, on the borrower. A co-borrower's contacts are optional. | 422, validation_failed |
property.has_adu | You are attaching an add-on that applies only to a property with an accessory dwelling unit. | 422, semantic_validation_failed |
An order type may not accept every property type or every loan purpose. Read
loan_purposes and property_types on the product and send values from them; a
value the product does not accept is refused with 422.
A product on the current report standard
curl -s -X POST https://api.appraisalhost.com/v1/orders \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: los-88421-create-1' \
-d '{
"order_type_code": "SFR-1004-36",
"loan_type_code": "conventional",
"add_on_codes": ["rent_schedule"],
"due_date": "2026-10-02",
"lender_reference": "LN-2026-88421",
"rush": false,
"certified_appraiser_required": true,
"appraiser_instructions": "Gate code 4417. Call the listing agent for access.",
"loan": {
"purpose": "purchase",
"number": "88421",
"client": "Example Mortgage Group",
"purchase_price": "415000.00",
"currency": "USD"
},
"property": {
"address": {
"street": "100 Example Avenue",
"unit": "Unit 2",
"city": "Springfield",
"state": "IL",
"postal_code": "62701"
},
"type": "single_family",
"occupancy": "primary_residence",
"has_adu": true
},
"borrowers": [
{
"role": "borrower",
"first_name": "Sample",
"last_name": "Borrower",
"receives_status_updates": true,
"contacts": [
{ "type": "email", "role": "home", "value": "sample.borrower@example.com" },
{ "type": "phone", "role": "cell", "value": "+1-217-555-0142" }
]
}
],
"parties": {
"real_estate_agent": {
"first_name": "Sample",
"last_name": "Agent",
"contacts": [
{ "type": "phone", "role": "cell", "value": "+1-217-555-0190" }
]
},
"additional_contacts": [
{ "purpose": "status", "name": "Processing Desk", "email": "processing@example.com" }
]
},
"notes": [
{ "type": "order", "text": "Borrower prefers a morning appointment." }
]
}'
{
"id": "ord_9TBK4C2QFA7M",
"order_number": "2026-1043",
"lender_reference": "LN-2026-88421",
"status": { "code": "new", "label": "New Order", "changed_at": "2026-09-17T14:32:05Z" },
"order_type": {
"code": "SFR-1004-36",
"name": "Single Family Residential, current report standard",
"report_format": "uad_3_6",
"appraiser_certification": "none"
},
"loan": {
"purpose": "purchase",
"number": "88421",
"purchase_price": "415000.00",
"currency": "USD",
"loan_type": { "code": "conventional", "name": "Conventional" },
"add_ons": [{ "code": "rent_schedule", "name": "Rent Schedule" }]
},
"dates": {
"created_at": "2026-09-17T14:32:05Z",
"updated_at": "2026-09-17T14:32:05Z",
"due_date": "2026-10-02",
"appointment_at": null,
"completed_at": null
},
"fees": { "appraisal_fee": "525.00", "currency": "USD" },
"documents": []
}
Store id and order_number against your loan file. id is what you call us
with. order_number is what a person will quote on the phone.
A product on the prior report standard
curl -s -X POST https://api.appraisalhost.com/v1/orders \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: los-88422-create-1' \
-d '{
"order_type_code": "DRIVEBY-2055",
"due_date": "2026-09-30",
"loan": { "purpose": "refinance", "number": "88422" },
"property": {
"address": { "street": "200 Example Lane", "postal_code": "62704" },
"type": "condominium",
"occupancy": "second_home"
},
"borrowers": [
{
"role": "borrower",
"first_name": "Example",
"last_name": "Borrower",
"contacts": [
{ "type": "email", "role": "home", "value": "example.borrower@example.com" }
]
}
]
}'
Appraiser certification, FHA and USDA
appraiser_certification on the product says which appraiser certification it
requires, and it is what the case number rule follows:
appraiser_certification | What it means | loan.fha_case_number |
|---|---|---|
none | No special certification. | Not used. |
fha_required | Only an FHA approved appraiser may take it. | Required. Omitting it is refused with 422. |
fha_optional | An FHA approved appraiser may take it. | Accepted, not required. |
usda | A USDA product. | Required. Omitting it is refused with 422. |
After the order is accepted
A create returns 201 and the order. An order we can place straight away is at
new, and stays there until the appraisal management company assigns an
appraiser. An order that needs a review by the company first, because of the
product, the loan type or the property, is at pending_review and moves to new
when the company places it. Both are normal, and you will see the order move with
order.status_changed.
A request we can refuse on its own terms, such as an unknown code or a code that
does not apply to the product, is refused with 422 instead, and no order is
created.
3. Follow the order
The catalog below is the complete set of statuses this interface reports. An order is always reported with the status the lender sees, in the same words the lender sees in the portal. Not every step inside the appraisal management company produces a status change, so treat each status as a fact about now.
code | label | What it means |
|---|---|---|
pending_review | Pending Review | Received, and with the appraisal management company for a review before it is worked. Nothing is wrong. You will receive order.status_changed when it moves. |
new | New Order | Received. Not yet assigned. |
appraiser_assigned | Appraiser Assigned | An appraiser has the assignment. |
appraiser_accepted | Appraiser Accepted | The appraiser has accepted it. |
borrower_contacted | Borrower Contacted | The appraiser has reached the contact. |
left_message_for_borrower | Left message for borrower / broker | The appraiser has tried the contact and left a message. |
appointment_scheduled | Appointment Scheduled | An inspection appointment is set. dates.appointment_at carries it. |
awaiting_review | Report Submitted, Awaiting Review | The report has been submitted and is in review before delivery. |
report_complete | Report Complete | The report has been delivered. The documents are on the order. |
report_rejected_for_correction | Report Rejected for Correction | The report was sent back for correction before delivery. |
revision_requested | Correction Requested By the Lender | A correction has been requested on a delivered report. |
reconsideration_requested | Request a reconsideration of value | A reconsideration of value has been requested. |
revised_report_complete | Revised Report Completed | A revised report has been delivered. |
on_hold | On Hold | Work is paused. |
off_hold | Off Hold | Work has resumed after a hold. |
cancelled | Order Cancelled | The order was cancelled. |
reactivated | Order Reactivated | A cancelled order has been put back into production. |
The labels above are one company's wording, shown as an example. Another company may word the same code differently, and a few labels are ours rather than the company's, because the status they stand for is internal to the company.
Not every status occurs at every company: a company may not use one at all. Treat the catalog as the full set of what you may receive, never as a sequence you must see.
Two rules for handling statuses:
- Branch on
code, displaylabel. An appraisal management company may reword its own labels. Codes do not change. - Do not assume a fixed sequence. Orders skip statuses, repeat them, and go backwards. An order can be delivered, corrected and delivered again. Treat each status as a fact about now, not a step in a queue.
off_hold and reactivated are transitional: they say what just happened, not
what the order is doing. An order at either moves on to its working status
shortly afterwards, so read the order again when you see one rather than
treating it as a resting state.
Webhooks are the primary way to learn about change. Poll only to reconcile:
curl -s 'https://api.appraisalhost.com/v1/orders?updated_since=2026-09-18T00:00:00Z&per_page=50' \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8'
updated_at moves when anything you can see on the order changes: its status,
its dates, its fee, its documents, its messages and its own fields.
updated_since is inclusive to the second, so overlap your windows by a second
or two rather than trusting an exact boundary.
4. Hold, resume, cancel
These are the rules this interface enforces. The appraisal management company's
own screens are slightly wider in places, so an order you cannot hold here may
still be held by the company on request. When the order's current status does not
allow an action, we answer 409 with code action_not_allowed_in_status and the
order's current status in current_status.
| Action | Allowed when | Refused with 409 when |
|---|---|---|
hold | The order is open and not already on hold, and no report has been delivered. | The report has been delivered (report_complete, revised_report_complete), a correction is open (revision_requested), the order is cancelled, or it is already on hold. |
resume | The order is on hold. | Any other status. |
cancel | The order is open and no report has been delivered. | The report has been delivered, a correction is open, or the order is already cancelled. A held order must be resumed first. |
curl -s -X POST https://api.appraisalhost.com/v1/orders/ord_9TBK4C2QFA7M/hold \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8' \
-H 'Content-Type: application/json' \
-d '{ "reason": "Borrower is renegotiating the purchase price." }'
{
"id": "ord_9TBK4C2QFA7M",
"order_number": "2026-1043",
"status": { "code": "on_hold", "label": "On Hold", "changed_at": "2026-09-19T11:02:00Z" },
"previous_status": { "code": "appraiser_assigned", "label": "Appraiser Assigned" }
}
A refusal looks like this:
{
"code": "action_not_allowed_in_status",
"message": "An order with a delivered report cannot be cancelled.",
"current_status": "report_complete",
"details": [
{
"field": "status",
"code": "current_status",
"value": "report_complete",
"message": "The report has already been delivered."
}
],
"correlation_id": "req_01J9Z3D6H9K2M5P8R1T4W7Y0"
}
Branch on current_status, the top level field. Every 409 that refuses an
action because of where the order has got to carries it, so you never have to
walk details, and never have to read message. details[].value carries the
same machine readable value for anything else at fault. message is for a
person and may be reworded at any time.
Send a reason. The appraisal management company and the appraiser both see it, and it saves a phone call. Note that a hold stands the appraiser down and remembers them, so a resume puts the order back where it was.
If the company cannot take an order on at all, it cancels it: you receive
order.cancelled with a reason, and the order is at cancelled. You learn it
within seconds rather than by noticing an order that never moved.
Some companies do not let a lender cancel at all. Then the call is refused with
403 and code action_not_permitted_for_client, and the way to ask is a
message on the order.
5. Corrections and reconsiderations of value
A revision request is how a lender asks for something to change after a report has been delivered.
kind: "correction"asks the appraiser to fix or clarify the report.kind: "reconsideration_of_value"asks the appraiser to reconsider the opinion of value. At least one acknowledgement is required: that a prior appraisal was provided, or that comparable sales were provided. Without one, the request is refused with422.
A request is accepted while the order is at report_complete,
revised_report_complete, revision_requested, reconsideration_requested or
cancelled. In any other status it is refused with 409.
Attach your evidence. Upload it first and quote the document ids, or send it inline:
curl -s -X POST https://api.appraisalhost.com/v1/orders/ord_9TBK4C2QFA7M/revision-requests \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8' \
-H 'Content-Type: application/json' \
-d '{
"kind": "reconsideration_of_value",
"reason": "Three closed sales within 0.4 miles support a higher value.",
"acknowledgements": {
"prior_appraisal_provided": false,
"comparable_sales_provided": true
},
"document_ids": ["doc_2KM7Q0VZTC93"]
}'
{
"id": "rr_6PD3K8YWQN25",
"order_id": "ord_9TBK4C2QFA7M",
"kind": "reconsideration_of_value",
"status": "submitted",
"reason": "Three closed sales within 0.4 miles support a higher value.",
"responses": [],
"created_at": "2026-09-30T10:04:18Z",
"updated_at": "2026-09-30T10:04:18Z"
}
We fill the rest of the record the company needs from the order and from your
credential, so there is nothing else to send. If the order has no loan number,
send loan.number on the order first.
A request starts at submitted, because many companies review it before it
reaches the appraiser. It moves to accepted when it is with the appraiser, to
declined when the company does not take it forward, and to completed once a
revised report has been delivered against it. Read GET /orders/{id}/revision-requests
for the thread, and watch order.revision_requested and
order.revision_responded.
A revised report arrives as order.completed with "revision": true, and the
order lands at revised_report_complete.
6. Due dates and fees
Due dates. A due date you send on POST /orders is what the lender needs.
A due date you send on PATCH /orders/{id} is a REQUEST. The date on the order
changes only when the appraisal management company accepts it, and you learn the
outcome from order.due_date_changed:
{
"id": "evt_01M2WFE9G0VF1S24AE8RTAH2ZC",
"type": "order.due_date_changed",
"created_at": "2026-09-19T09:20:00Z",
"api_version": "1.0.0",
"data": {
"order_id": "ord_9TBK4C2QFA7M",
"order_number": "2026-1043",
"due_date": "2026-10-06",
"previous_due_date": "2026-10-02",
"requested_by": "lender"
}
}
requested_by is lender for a change you asked for and company for one the
appraisal management company made. The date can also move without a request from
you, for example when an appointment cannot be kept. Always take the date from the order or the event,
never from your own request.
Fees. The fee is read only through the API. fees.appraisal_fee is the fee
the lender is charged, and it is normally set when the order is created. It is
null when the product or an add-on has to be quoted by the appraisal management
company. Either way, a later change raises order.fee_changed with the old and
the new amount. There is no endpoint for
objecting to a fee or proposing another one: send a message on the order with
POST /orders/{order_id}/messages, and the company answers there.
What else you may amend. Some companies do not let a lender amend an order
at all. Then PATCH is refused with 403 and code
action_not_permitted_for_client, and the way to ask is a message on the order.
PATCH /orders/{id} accepts your own reference,
the loan number, the client and investor, the contacts and parties, the notes,
the appraiser instructions, and a due date request. An order carries one note of
each type, and a note you send is added to the note of that type rather than
replacing it; notes have no ids and cannot be edited or removed here. The property, the borrower
names, the order type, the loan type and the add-ons cannot change once an order
exists: cancel and place a new order instead. Amending a closed order is refused
with 409.
7. Messages
curl -s -X POST https://api.appraisalhost.com/v1/orders/ord_9TBK4C2QFA7M/messages \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8' \
-H 'Content-Type: application/json' \
-d '{
"recipient": "manager",
"subject": "Access arrangements",
"body": "The listing agent will meet the appraiser on site."
}'
recipienton a message you send ismanager(the appraisal management company) orappraiser.- A company that keeps appraiser contact in its own hands refuses
appraiserwith422and coderecipient_not_allowed. Send it tomanagerinstead. - On a message you read,
recipientmay also belender: that is a message addressed to you. Accept all three values. - Attach a file by uploading it first and quoting its id in
document_ids. A message from the company or the appraiser may carry documents of its own, inattachments; they are on the order as well. GET /orders/{order_id}/messagesreturns the thread the lender is party to, oldest first. Internal notes between the company and the appraiser are not included.- A reply from the company or the appraiser raises
order.message_posted. Your own messages do not.
8. Supporting documents
Upload the purchase and sale contract, an engagement letter, comparable sales, or anything else the appraiser needs. A document you upload is visible to the appraisal management company and to the assigned appraiser.
curl -s -X POST https://api.appraisalhost.com/v1/orders/ord_9TBK4C2QFA7M/documents \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8' \
-F 'kind=supporting' \
-F 'purpose=sales_contract' \
-F 'description=Purchase and sale contract' \
-F 'file=@purchase_and_sale.pdf'
{
"id": "doc_2KM7Q0VZTC93",
"kind": "supporting",
"filename": "purchase_and_sale.pdf",
"content_type": "application/pdf",
"size_bytes": 412998,
"created_at": "2026-09-17T14:40:11Z"
}
- 25 MB per file. A larger file is refused with
413. - PDF, JPEG, PNG, TIFF, ZIP, plain text, XML and the common office document
types are accepted. Anything else is refused with
415. kindmust besupportingon an upload. A report, a report data file, an invoice or a certificate is produced by the appraisal management company, never uploaded by a lender.purposeis optional and says what the file is:engagement_letter,sales_contract,prior_reportorother. Leave it out andotheris assumed.- Small files can also ride along on
POST /ordersin thedocumentsarray, base64 encoded. Prefer the upload endpoint for anything over a megabyte or two.
9. Receiving the finished report
When the report is delivered, the order moves to report_complete and
order.completed fires with every delivered file listed. Each file is a
separate document with its own kind and its own id.
{
"id": "evt_01M3Q5WZA8V0AB3B4S4B8E3XC5",
"type": "order.completed",
"created_at": "2026-09-29T18:12:45Z",
"api_version": "1.0.0",
"data": {
"order_id": "ord_9TBK4C2QFA7M",
"order_number": "2026-1043",
"status": { "code": "report_complete", "label": "Report Complete", "changed_at": "2026-09-29T18:12:44Z" },
"report_format": "uad_3_6",
"revision": false,
"completed_at": "2026-09-29T18:12:44Z",
"documents": [
{ "id": "doc_3XH8M1PLQW60", "kind": "report_pdf", "filename": "report_2026-1043.pdf", "content_type": "application/pdf", "size_bytes": 2841773, "created_at": "2026-09-29T18:12:44Z" },
{ "id": "doc_5RJ2N7VKTB41", "kind": "report_data", "filename": "report_2026-1043.zip", "content_type": "application/zip", "size_bytes": 1044210, "created_at": "2026-09-29T18:12:44Z" },
{ "id": "doc_8QL4P9WMYC72", "kind": "invoice", "filename": "invoice_2026-1043.pdf", "content_type": "application/pdf", "size_bytes": 88120, "created_at": "2026-09-29T18:12:45Z" }
]
}
}
Which documents arrive
kind | uad_2_6 | uad_3_6 | What it is |
|---|---|---|---|
report_pdf | Yes | Yes | The appraisal report as a PDF. |
report_data | Yes, an XML file | Yes, a package in ZIP form | The report data. This is the one file whose form differs between the two standards. |
invoice | When the company invoices through the platform | When the company invoices through the platform | The invoice for the order. Always its own file. |
compliance_certificate | When the company issues one | When the company issues one | The compliance certificate. |
borrower_certificate | When the company issues one | When the company issues one | The borrower delivery certificate. |
ssr | When the order goes through a collateral delivery portal | When the order goes through a collateral delivery portal | A submission summary report. There may be more than one. |
review_report | When the company's review process produces one | When the company's review process produces one | A quality review report produced by the appraisal management company's own review process, when the company provides it to lenders. It is not something a lender orders through this API. |
supporting | Either side, any time | Either side, any time | Anything supplied to support the order. |
The rule to build against: the package replaces the report data file and nothing else. On the current standard the report data arrives as a ZIP package, and the invoice, the certificates and every other delivery document remain separate files exactly as they are on the prior standard. Do not unpack the ZIP looking for an invoice.
Downloading
List the documents on the order:
curl -s https://api.appraisalhost.com/v1/orders/ord_9TBK4C2QFA7M/documents \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8'
Then ask for a link one document at a time:
curl -s https://api.appraisalhost.com/v1/documents/doc_5RJ2N7VKTB41 \
-H 'Authorization: Bearer aht_at_7Qk2rX9wTm4ZbN1sV6yH0pL8'
{
"id": "doc_5RJ2N7VKTB41",
"order_id": "ord_9TBK4C2QFA7M",
"kind": "report_data",
"filename": "report_2026-1043.zip",
"content_type": "application/zip",
"size_bytes": 1044210,
"created_at": "2026-09-29T18:12:44Z",
"download": {
"url": "https://api.appraisalhost.com/v1/download/doc_5RJ2N7VKTB41?expires=1790705864&signature=4f1c8e2b9a7d5c3f6e0b8a2d4c6f1e9b",
"expires_at": "2026-09-29T18:17:44Z"
}
}
Follow the link with a plain GET and no Authorization header: the signature in
the link is the authorization. The expires value in the URL is the same
instant as expires_at, in Unix seconds.
The link is valid for five minutes and may be used more than once inside that window. Fetch a fresh one when it expires rather than storing links, and store the bytes you downloaded rather than the URL.
A document you are not entitled to see returns 404, not 403, so that ids
cannot be probed.
Later documents
Documents also arrive after delivery: a submission summary report once the
collateral portal answers, a corrected invoice, a revised report. Each one
raises order.document_added. Handle that event rather than assuming the file
list is final at order.completed.