Deal status
The stages, the reason codes and the rules every channel applies when you tell us where a deal stands.
Every way you can tell us where a deal stands reads the same stage list and the same
reason codes: the API, your private inbound link, a reply to the referral email and the
Lender Hub. Pick one of them as your team's main channel and report every stage there,
including funded. The Lender Hub board does not yet show what arrives through the other
channels (see From the Lender Hub).
The stages
Report the stage as the deal moves on your side, in this order.
- In progress:
received,contacted,documents_requested,in_underwriting. - Offer:
approved,offer_made,offer_accepted,contracts_sent,contracts_signed. - Final:
funded,declined,not_proceeding,duplicate.
| Stage | Label |
|---|---|
received | Received |
contacted | Contacted |
documents_requested | Documents requested |
in_underwriting | In underwriting |
approved | Approved |
offer_made | Offer made |
offer_accepted | Offer accepted |
contracts_sent | Contracts sent |
contracts_signed | Contracts signed |
funded | Funded |
declined | Declined |
not_proceeding | Not proceeding |
duplicate | Duplicate or existing customer |
You do not have to report every stage. A deal can go from received straight to
declined, and the stage you send last is the one the deal shows.
What each stage needs
A request that misses one of these is refused with 400 and a message that names the
field and the values it accepts. Nothing is recorded.
declined(your credit decision) andnot_proceeding(the client stopped) need areason_code.duplicate(you already have this business) impliesduplicate_or_existing_customer; send no code, or that one.reason_codeotherneeds areason_notein your own words.fundedneeds the amount you funded:funded_amounton the API,amounton the inbound link.- A
reason_codesent with any other stage is ignored. Areason_notemay go with any stage.
The stage follows the reason when the reason belongs to the other side, so nobody tells a client that a lender declined them when they walked away themselves:
declinedwithmerchant_withdrew,merchant_unresponsiveormerchant_declined_offeris recorded asnot_proceeding.not_proceedingwith one of your own reasons, such asinsufficient_revenue, is recorded asdeclined.duplicate_or_existing_customerwithdeclinedornot_proceedingis recorded asduplicate.statements_insufficient,documents_missingandotherfit either side and keep the stage you sent.
Reason codes
- Your decision:
insufficient_revenue,time_in_business,credit_score,adverse_history,affordability,existing_debt,negative_balance_days,industry,location_not_served,amount_out_of_range,pricing_not_viable,does_not_meet_criteria,no_business_bank_account,identity_or_fraud,invalid_lead. - Either side:
statements_insufficient,documents_missing,other. - The client's:
merchant_unresponsive,merchant_withdrew,merchant_declined_offer. - A duplicate:
duplicate_or_existing_customer.
| Reason code | Label |
|---|---|
insufficient_revenue | Revenue too low |
time_in_business | Not trading long enough |
credit_score | Credit score below threshold |
adverse_history | Adverse history (defaults, CCJs, insolvency, liens) |
affordability | Repayments not affordable |
existing_debt | Too much existing debt or stacking |
negative_balance_days | Negative days or returned payments |
industry | Industry not funded |
location_not_served | Location or owner residency not served |
amount_out_of_range | Amount outside the lenderโs range |
pricing_not_viable | Could not offer suitable pricing |
does_not_meet_criteria | Does not meet minimum criteria |
statements_insufficient | Bank statements missing, too few or unreadable |
no_business_bank_account | No business bank account |
documents_missing | Other documents missing |
identity_or_fraud | Identity not verified or fraud concern |
invalid_lead | Contact details wrong or not a real business |
merchant_unresponsive | Client did not respond |
merchant_withdrew | Client did not proceed |
merchant_declined_offer | Client turned down the offer |
duplicate_or_existing_customer | Duplicate or existing customer |
other | Other (note required) |
The reason decides what happens next. After declined or duplicate the request goes on
to the other lenders it suits, unless the reason is identity_or_fraud or invalid_lead.
After not_proceeding it does not: that was the client's decision.
The client and any referral partner never see your reason_note. The client is shown a
neutral sentence for the reason code.
The earlier Hub codes are still accepted and recorded as the current ones: sector as
industry, time_trading as time_in_business, documentation as documents_missing,
pricing as pricing_not_viable.
By API
POST /deals/{ref}/status with your API key.
curl -X POST https://api.capvant.com/v1/deals/93A41205CE/status \
-H "X-API-Key: $CAPVANT_API_KEY" -H "content-type: application/json" \
-d '{
"status": "declined",
"reason_code": "insufficient_revenue",
"reason_note": "Average monthly deposits under our 15k minimum."
}'The answer is the deal, plus the stage and reason as recorded: lender_stage,
lender_reason_code and lender_reason_note. lender_stage can differ from the status
you sent when the reason belongs to the other side. GET /deals and GET /deals/{ref}
carry the coarse lender_status only, so keep this answer if you need the stage later.
stageis accepted in place ofstatus, with the same values; when both are sent,stagewins.- Earlier values still work:
in_reviewandin_progressare recorded asin_underwriting,offerasoffer_made,withdrewasnot_proceedingwithmerchant_withdrew,lost_on_termsasnot_proceedingwithmerchant_declined_offer. - Every accepted change fires
deal.updatedto the endpoints you registered for it.
The free-text reason is deprecated
The earlier reason field still works for one release when no reason_code is sent: we
read the code from your words, record other when nothing fits, and keep the text as the
note. The answer then carries Deprecation: true and a Link header pointing at this
page. Send reason_code, with reason_note for your own words.
By private inbound link
The link on your Lender Hub integration page,
https://api.capvant.com/v1/inbound/status/ followed by your secret, takes the same
stages and reason codes with nothing to authenticate: the secret is the credential, so
keep it out of shared documents and rotate it in the Hub if it leaks.
curl -X POST "$CAPVANT_INBOUND_URL" \
-H "content-type: application/json" \
-d '{"dealRef": "93A41205CE", "status": "funded", "amount": 85000}'- Find the deal with
dealRef(our reference) orid(the lead id you returned when we created the lead). Either is enough. statustakes a stage, an earlier value or your own CRM stage name. Common names are understood as they are: "Working - Application Out" isdocuments_requested; "DNQ" and "Closed - Not Converted" aredeclinedwithdoes_not_meet_criteria; "Not a Lead" isdeclinedwithinvalid_lead; "Deal Lost" isnot_proceedingwithmerchant_declined_offer. Any other name can be mapped to a stage in the Lender Hub.reason_code, or your own words inreason(we read the code from them).amountforfunded.- The answer is
{ "ok": true, "dealRef": "93A41205CE", "status": "funded" }, wherestatusis the stage recorded.
By email
Reply to the referral email with a short first line, for example "Funded ยฃ85,000" or "Declined: turnover below our minimum". Deals by email lists the phrases we record automatically; anything else is read and recorded by our team, so it shows later. Give the reason after a decline.
From the Lender Hub
The Hub board has five columns: New, In review, Offer made, Funded and Closed. Moving a deal to Closed asks for the reason, and moving it to Funded asks for the amount.
Every stage picked on the board reaches the deal itself, exactly like a status sent by API, the inbound link or email: Funded with its amount marks the deal funded, Closed records the reason. The other way round works too: a status reported by API, the inbound link or email moves the card on the board.
Errors you can meet
| Answer | What it means |
|---|---|
400, status is required: one of received, ... | No status (or stage) in the body. |
400, status "..." is not one of ... | A value that is not a stage or an earlier value. On the inbound link: not a stage and not mapped in the Hub. |
400, reason_code is required when status is declined: one of ... | A decline or not proceeding without a code (and, on the inbound link, without words we can read one from). |
400, reason_code "..." is not one of ... | A code that is not in the list (and not an earlier Hub code). |
400, reason_note is required when reason_code is other. | other without a note. |
400, funded_amount is required when status is funded. | Funded without the amount, or funded_amount must be a positive number. for an amount that is not one. |
404, not_found | No deal routed to you has this reference (or, on the inbound link, this id). |
401, unauthorized | A missing or revoked API key, or an unknown inbound secret. |
The inbound link words a few of these differently, naming amount instead of
funded_amount; the field and the rule are the same.
