Fincheck

Changelog

Changes to the FincheckEngine API that affect your integration.

Changes to the FincheckEngine API that affect your integration, newest first.

14 October 2026

A page per intent

Each intent now has its own docs page at /docs/intents/{id}: how to select it, its fields and rules, and an example request it accepts. The page always shows the current rules and can be printed or saved as PDF. Open it from Intent Fields. Nothing changes in the API.

13 October 2026

Quote or apply now

  • application_method is documented and checked. Send get-quote (the default) or apply-now on POST /offer. On v2 any other value is rejected with not_in_enum; on v1 the value is matched ignoring case and spaces, and an unknown value is treated as get-quote. See Quote or apply now.
  • End-to-end needs an apply-now offer. "type": "apply-now" on POST /accept now starts an end-to-end application only when the lead was offered with application_method: "apply-now", and, for a partner that prices live, its match included live_quotes. Otherwise the accept continues as a normal referral. This applies to v1 and v2. See Applying end to end.
  • Matches without a price. A partner with live_scoring_api: true can appear in matches without live_quotes. It is offered without a price for that applicant. Show the match as you would any other.

12 October 2026

New API origins

The v2 API uses new origins. Changing only /api/v1 to /api/v2 on the old host is not enough.

  • UAT: https://api.engine-v2.uat.fincheck.co.za/api/v2
  • Production: https://api.engine-v2.fincheck.co.za/api/v2

Use the key for the same environment as the origin. Data and credentials do not cross environments.

7 October 2026

v2 validation

These changes apply to v2 integrations only. v1 is unchanged. Rows of POST /lead/batch follow the same rules.

  • One set of rules. A request is checked against the rules every lead follows plus the rules of the intent it selects. GET /intent returns that contract, so read an intent's required fields, limits and custom fields from there rather than hardcoding them. Every field with a problem is reported at once, with the first problem for each field.
  • Selecting the intent. intent and intent_id must name the same intent when both are sent; otherwise intent is reported as invalid_value ("must match intent_id"). Sending neither is one problem on intent ("send one of: intent, intent_id"). An unknown or inactive intent is answered on its own, before field problems.
  • intent_unavailable. When an intent's rules are temporarily unusable, POST /lead, POST /offer, POST /lead/batch and GET /intent/{id} return 503 {"code": "intent_unavailable", "message": "This intent is temporarily unavailable."}. Retry later with backoff. The intent is left out of the GET /intent list until it recovers.
  • Names. Letters from any alphabet, spaces, hyphens, straight or curly apostrophes and full stops, with at least one letter: Zoë, Ané, D’Angelo, Anne-Marie, C.J.. A failing name is invalid_format rather than invalid_value.
  • Email. An ASCII address with a dotted domain. user@localhost and non-ASCII addresses are rejected.
  • Mobile numbers. Formatted numbers such as +27 82 123 4567 are accepted and stored as 0821234567. A number that is not a South African mobile is invalid_format, whatever its length; too_short and too_long are no longer returned for it.
  • ID numbers. A malformed ID number has one message, must be a valid RSA ID number.
  • partner_ids. Send partner_ids. The singular partner_id is not supported and is rejected with unsupported_field when it has a value.
  • Blank and null. Omit optional fields when no value is available. A blank or null value counts as not sent; for a required field that is required.
  • Error messages are sentences. Every v2 message starts with a capital letter and ends with a full stop, for example Lead not found. and This intent is not accepting leads.. Codes and HTTP statuses are unchanged, so branch on code. Errors sent before your key is identified still have only error and no code, and v1 responses are unchanged.
  • Batch rows. Row errors keep the same shape ({"row": 3, "errors": {"field": "message"}}) with the new messages. A blank cell means not sent, text in a numeric column is rejected, decimal money is rounded to whole rand, and a partner_ids cell is a comma- or semicolon-separated list.

See Intent Fields, Sending a Lead and Batch Import.

6 October 2026

Field rules

These changes apply to v2 integrations only. v1 is unchanged.

  • Allowed values and ranges. Request fields are checked against published rules, not just their JSON type: fixed lists such as payment_frequency (weekly, fortnightly, monthly, other), ranges such as repayment_period (1–120 months) and payday (1–31), non-negative amounts, net_income not above gross_income, text lengths, a South African mobile number (06x, 07x or 081–084), and an applicant aged 18–100. A value outside its rule returns 422 naming the field.
  • New employment_type. full_time, part_time, self_employed, contract, commission, pensioner, student, homemaker, unemployed or other. When employed is left out it is set from employment_type.
  • Rules per intent. GET /intent returns each intent's schema, a JSON Schema with its required fields and limits, in place of fields. An intent's required fields are now enforced on POST /lead and batch rows as well as POST /offer.
  • Field tables. Every guide lists its request and response fields with type and allowed values, and Intent Fields shows each intent's rules.

Error codes

These changes apply to v2 integrations only. v1 is unchanged.

  • code on every error. Error bodies carry a stable string code next to message, for example {"code": "lead_already_accepted", "message": "This lead has already been accepted."}. Branch on code; messages may be reworded.
  • A code on every field problem. In 422 validation responses each field in errors lists its problems as {"code", "message"} entries, for example "gross_income": [{"code": "required", "message": "is required"}] (codes such as required, invalid_type, not_in_enum, below_minimum).
  • Generated error tables. Errors lists every code with its status, message, cause and what to do.

Duplicate submissions

These changes apply to v2 integrations only. v1 is unchanged.

  • Your own leads only. Sending an applicant again is checked against your own leads. You never receive another affiliate's lead id.
  • result on every lead and offer response. created for a new lead, duplicate when the lead you already have is returned. On POST /lead that response has status Lead already received. POST /offer returns result and does not include status.
  • New lead after a send. When your earlier lead was already sent to a partner, a repeat creates a new lead that only goes to partners the applicant has not reached recently.
  • Named partners. A partner in partner_ids that already received the applicant is reported as already sent to this partner instead of being sent again.
  • Accepting. POST /accept works only for your own leads (404 otherwise) and returns 422 lead_already_accepted for a lead already sent.
  • Batch. Rows follow the same rules, including against your earlier uploads. A partner_id column is rejected; use partner_ids.

See Duplicate Submissions.

2 October 2026

Decimal amounts and placeholder values

  • Money fields (gross_income, net_income, loan_amount_required, expenses) accept any JSON number; decimals are rounded to whole rand. Numeric strings are still rejected.
  • Placeholders. On optional fields, "", null, unknown, n/a, not specified, and undefined (any letter case) mean not provided. See Placeholder values.

30 September 2026

v2 responses and requests tightened

These changes apply to v2 integrations only. v1 is unchanged.

  • Offers. Matches no longer include company_logo_path, live_score, or userable. partner_type and probability_conditions are at the top level of each match, and live_quotes carries the partner's quote.
  • Typed requests. POST /lead and POST /offer must be sent as application/json (otherwise 415), with each field in its JSON type. Numeric strings such as "25000" and words such as "yes" are rejected with 422 naming the field.
  • Removed request fields. The singular partner_id on POST /lead and POST /offer, and live_score on POST /accept, are rejected with 422. Use partner_ids and live_quotes.
  • Response bodies. code is no longer returned; read the HTTP status. Errors use message throughout, and validation errors say Validation failed.
  • Lead lookups. GET /lead/{hashid} and GET /accept/{hashid}/link return only your own leads. Any other id returns 404.

See Upgrade to v2 for before-and-after examples.

29 September 2026

API v1 deprecated

API v1 is closed to new integrations and will be retired. No retirement date has been set yet; it will be announced here with advance notice.