{
  "service": "A lender’s own operation, hosted",
  "version": "1.0.0",
  "what": "Calls a lender’s own program makes against the records its hosted pages keep, under /v1/l/<lender id>/: applications from its own front end, sign-in links for its staff, the work queue, case files and every action its staff take on them for a console of its own, the payments and requests its borrowers made, the daily run and the funder pack.",
  "key": "Each call needs that lender’s own API key; a borrower’s or a staff member’s session is never accepted. A live key is refused by a lender still in the sandbox or before launch, and a test key by a live lender.",
  "stores": "The lender’s records, where the lender keeps them: in the sandbox nothing outlives the process, before launch only test records, and real ones only once keeping them is approved.",
  "endpoints": {
    "GET /v1/l/:tenant/score/model-borrower": {
      "what": "The lender’s model borrower for a loan type (?type=sacc, macc, personal, secured, car or business; the first it offers if none): its name, its own rating, the shared profile for the type, and every one of its loans that moved it."
    },
    "GET /v1/l/:tenant/score/history/:loanRef": {
      "what": "A loan’s rating history: the assessment against the model borrower, measure by measure, then every change since, each with its day, reason, risk class before and after, and the gap to the model borrower; its risk class now, D once written off or 90 days past due."
    },
    "GET /v1/l/:tenant/contract-templates": {
      "what": "Your contract templates, and which version of each is published."
    },
    "POST /v1/l/:tenant/contract-templates": {
      "what": "A new template, or one from an example: { \"starter\": \"mutual-nda | services | contractor | referral | variation | personal-guarantee | loan-sacc | loan-macc | loan-personal | loan-car | loan-mortgage | loan-business | loan-business-supplier-pay | loan-business-invoice-advance | loan-business-line-of-credit | loan-business-equipment\" }, or { \"name\", \"title\", \"text\", \"signers\": [{ \"label\", \"side\" }], \"fields\": [] }. Each {{name}} in the wording that is not described becomes a field."
    },
    "GET /v1/l/:tenant/contract-templates/:id": {
      "what": "One template: its draft and its latest version."
    },
    "POST /v1/l/:tenant/contract-templates/:id/publish": {
      "what": "Publish the draft as the next version. Wording that began as an example needs { \"reviewed\": true } for real records.",
      "body": {
        "reviewed": "true: it has been reviewed for your use"
      }
    },
    "GET /v1/l/:tenant/contracts?status=&q=": {
      "what": "Your contracts, newest first, each with its status and who has signed."
    },
    "POST /v1/l/:tenant/contracts": {
      "what": "A contract from a template’s latest version, or from wording of its own. It stays a draft unless \"send\" is true; then it answers with each signer’s link.",
      "body": {
        "template": "a template’s id",
        "title": "optional; the template’s if left out",
        "text": "wording of its own, or a change for this one",
        "values": "{ field: value }",
        "signers": "[{ \"role\", \"name\", \"email\" }]",
        "startsOn": "YYYY-MM-DD",
        "endsOn": "YYYY-MM-DD",
        "termMonths": "whole months, if there is no end date",
        "renewal": "none | remind | auto",
        "links": "{ \"application\" | \"loan\": a reference }",
        "send": "true to send it now",
        "signWithinDays": "1 to 30"
      }
    },
    "GET /v1/l/:tenant/contracts/:id": {
      "what": "One contract, with its history and whether that history is unchanged."
    },
    "POST /v1/l/:tenant/contracts/:id/send": {
      "what": "Send a draft for signature: its document is frozen and fingerprinted, and each signer whose turn it is gets their link, by email where they have one and you may send it. Answers with the links."
    },
    "POST /v1/l/:tenant/contracts/:id/remind": {
      "what": "Send a reminder to everyone it is waiting on who has not had one today. Answers with their links."
    },
    "POST /v1/l/:tenant/contracts/:id/void": {
      "what": "Withdraw a draft or a contract out for signature. A signed one cannot be: amend it.",
      "body": {
        "reason": "why"
      }
    },
    "GET /v1/l/:tenant/contracts/:id/pdf": {
      "what": "The contract as a PDF, with every signature so far."
    },
    "POST /v1/l/:tenant/contracts/run": {
      "what": "Do what is due today: reminders, contracts past their day, notices of an end date and renewals. Where Creditcrest runs your day this happens by itself."
    },
    "GET /v1/l/:tenant/book/funder?asAt=": {
      "what": "The funder pack for a lender whose records Creditcrest keeps: loan tape, borrowing base, vintage curves, roll rates, complaints and refunds. Needs that lender’s API key.",
      "query": {
        "asAt": "YYYY-MM-DD, the as-at day; today in Sydney if left out"
      }
    },
    "GET /v1/l/:tenant/loans?status=&band=&hardship=&asked=&product=&q=&sort=&page=": {
      "what": "Every funded loan, as the LoanManager dashboard lists it: balance, days past due and band, risk class, hardship and flags, with the portfolio’s tiles. Needs that lender’s API key.",
      "query": {
        "status": "open | current | arrears | hardship | closed | paid-out | written-off | written-off-hardship",
        "band": "current | 1-30 | 31-60 | 61-90 | 91-120 | 120+",
        "hardship": "request | undecided | arrangement | any | ever | none",
        "asked": "statement (a payout statement still owed) | complaint (a complaint on file)",
        "product": "a product key",
        "q": "a loan or application reference, customer id, name or mobile",
        "sort": "priority | dpd | balance | principal | next | risk | borrower | reference",
        "page": "from 1, 25 loans a page"
      }
    },
    "GET /v1/l/:tenant/loans/:loanRef": {
      "what": "One loan: its account as the ledger runs it today — schedule, every transaction with its allocations, balances, payout figure, hardship — with its repayment history month by month, its score history and the borrower’s requests. Needs that lender’s API key."
    },
    "GET /v1/l/:tenant/loans/:loanRef/actions?by=": {
      "what": "The servicing actions on one loan, as its LoanManager page offers them, for a lender building its own staff console: each with whether it is open on the loan now and why not, the roles that may take it, and its fields — kind (money, day, choice, choices, text or yes), label, whether required, choices and default. With the lastSeq and requestsSeq to send it with. Needs that lender’s API key.",
      "query": {
        "by": "optional: a work email on the lender’s staff list, to say whether that person may take each (allowed)"
      }
    },
    "POST /v1/l/:tenant/loans/:loanRef/actions": {
      "what": "A servicing action on one loan, taken exactly as its LoanManager page takes it: the same checks, the same ledger, the same webhooks. by is the person it is recorded as, active on the lender’s staff list, and their role there decides what they may do. Written after the lastSeq and requestsSeq sent, so a change made since is a 409 conflict, never written over, and a call sent again is never recorded twice. Answers the events posted and the loan as GET /v1/l/:tenant/loans/:loanRef answers it; a payout statement, the statement too. Not charged: servicing is in the take-rate on each advance. Needs that lender’s own key, live for a lender whose records are live.",
      "body": {
        "action": "payment | settle | dishonour | fee | waive | refund | notice | decide | end-arrangement | write-off | payout-statement | default-notice | customer-paid | security-released",
        "by": "the work email of the staff member taking it, active on the lender’s staff list",
        "lastSeq": "the loan’s lastSeq, as you read it",
        "requestsSeq": "the loan’s requestsSeq, as you read it",
        "amount": "money, for payment, fee, waive, refund, customer-paid",
        "planAmount": "money, for decide",
        "on": "day, for payment, settle, dishonour, fee, end-arrangement, default-notice, customer-paid, security-released",
        "receivedOn": "day, for notice",
        "decidedOn": "day, for decide",
        "until": "day, for decide",
        "first": "day, for decide",
        "asAt": "day, for payout-statement",
        "method": "choice, for payment",
        "part": "choice, for fee, waive",
        "channel": "choice, for notice",
        "outcome": "choice, for settle, decide",
        "cadence": "choice, for decide",
        "payment": "choice, for dishonour",
        "notice": "choice, for decide",
        "request": "choice, for settle, payout-statement",
        "row": "choice, for fee",
        "to": "choice, for customer-paid",
        "reasons": "choices, for notice",
        "reference": "text, for payment, settle, customer-paid, security-released",
        "reason": "text, for payment, settle, dishonour, fee, waive, refund, decide, end-arrangement, write-off, default-notice",
        "statedReason": "text, for notice",
        "again": "yes, for payment",
        "overpay": "yes, for payment",
        "enforcement": "yes, for fee",
        "confirm": "yes, for write-off",
        "hardshipRelief": "yes, for write-off"
      }
    },
    "POST /v1/l/:tenant/applications/prefill": {
      "what": "What to fill your own form in with, once the applicant has proved both contacts: their details from their last application with you, or — for someone who signed up before applying — the name they saved. {found: false} for anyone else. The same keys as an application, and refused (not_open) while you take only sign-ups.",
      "body": "{contact: {email, mobile, emailToken, mobileToken}}, the tokens POST /v1/identity/contact/check gave back once each code was right",
      "answer": "{found, from: account | application, on, about: {firstName, lastName, dateOfBirth?, address?, timeAtAddress?}}: for the applicant to check and change, never to send unseen"
    },
    "POST /v1/l/:tenant/applications": {
      "what": "Submit a whole application: the same checks as the hosted pages, the answers sealed, the lender’s policy run for its staff, and the case put in its queue. Returns the reference and nothing about the outcome.",
      "body": "{start, contact: {email, mobile, emailToken?, mobileToken?}, about, statement: {csv} | {connection} | {later: true}, finances, consents: {key: true}, declaration: true}",
      "contact": "emailToken and mobileToken are the tokens POST /v1/identity/contact/check gives once the applicant types back the code sent to that address. Send both from your own form: only an applicant whose email and mobile are both proved is recorded as the lender’s customer, and only a customer signs in to their account — where they sign the contract and see the loan. Without them the application is taken and worked, but the contract cannot be signed.",
      "statement": "One of: {csv}, the bank’s CSV export as text; {connection, shownHash?}, a bank connection you made with POST /v1/l/:tenant/bank-connections (with a sandbox key, that same key), once it is ready — kept exactly as the hosted pages keep a connected bank, used once, for an applicant with the same last name, its bank data consent the one given at the bank (so consents need not send it); or {later: true}. With a connection, finances answers what the hosted finances screen asks beside the bank’s figures: figuresRight, with figuresReason when no, and creditOther, with creditOtherMonthly when yes. shownHash, from GET /v1/l/:tenant/bank-connections/:id, says your form showed the applicant exactly its figures: they are recorded with the answer. confirm is the older way to say what was confirmed of the figures read.",
      "finances": "{incomeSource, takeHome, incomeFrequency, nextIncomeDate, otherIncome?, change, changeType?, housing, dependants, expenses: {…}, hasCredit, creditMonthly?, otherDebts?, overdueNow?, hardship?, reduce?, reducePercent?, gambling, gamblingAnswers?} — with hasCredit true, yes or no for overdueNow (a repayment overdue now) and hardship (a hardship arrangement now or in the last 12 months); without credit neither is asked. otherIncome is other regular income a month, and otherDebts debts being paid off that are not credit (a debt collector’s plan) a month (form journey-5). The hardship answer is kept with the file for the lender’s staff and never given to a policy or a score. benefit and defaultOrCollection are no longer asked (form journey-4); sent, they are checked and kept, not sealed. Employment (form journey-6): with a statement whose wages reach the lender’s pay floor a month (journey.employmentPayFloor, $2,000 unless set), payRight (yes or no: the pay found is right); otherwise, or with payRight no, employmentStatus (full-time, part-time, casual, self-employed, not working, retired, centrelink) and, for someone working, employer, occupation and timeInJob (lt3m, 3-12m, 1-2y, 2-5y, 5y+), with abn optional if self-employed.",
      "not_a_decision": "An application received is not an approval. Nothing here approves or declines: the lender’s staff assess it."
    },
    "GET /v1/l/:tenant/requests/:loanRef": {
      "what": "What a borrower asked for on a loan: payments with their state (processing, settled or returned), hardship notices, complaints and payout statements."
    },
    "POST /v1/l/:tenant/requests/:loanRef/settle": {
      "what": "Settle or return a payment a borrower asked for. Settled, it becomes the payment on the account, once, whatever the number of times it is sent.",
      "body": {
        "requestSeq": "the seq of the payment requested event",
        "outcome": "settled | returned",
        "reference": "the payment’s reference in the lender’s system",
        "on": "YYYY-MM-DD, the day; today in Sydney if left out",
        "reason": "for a return, why"
      }
    },
    "GET /v1/l/:tenant/sign-ups": {
      "what": "The people who signed up before applying and said yes to the lender’s marketing emails: each one’s email address and first name, with the version of the question and when it was answered. Read it again before every send: anyone can say no on their account at any time, and an account not used is deleted. Pages of 200, from ?after=<the last customerId>."
    },
    "GET /v1/l/:tenant/support/:reference": {
      "what": "A hardship notice or complaint given on the support page, by its acknowledgement reference: what was asked, and the name and contact to reply to. The loan reference is as the person typed it, for the lender to match."
    },
    "POST /v1/l/:tenant/day": {
      "what": "The daily run: seals the day before for every funded account, and lists the debits, hardship and complaint deadlines, payout statements, processing payments and messages due. Where the lender’s payments are connected (Zepto, with payment collection allowed), each repayment due today on a loan whose borrower authorised a PayTo agreement is collected — never more than the ledger says is owed that day, one at a time — and goes on the ledger when Zepto reports it settled. It sends nothing else.",
      "body": {
        "asAt": "YYYY-MM-DD; today in Sydney if left out. A run for an earlier day lists what fell due then and collects nothing."
      }
    },
    "POST /v1/l/:tenant/staff-sessions": {
      "what": "A sign-in link to the lender’s operations console for one of its staff, lasting ten minutes and working once. The lender’s own key is needed outside the sandbox. Send a name and a role; or the work email of a person on the lender’s staff list, to sign them in as the list has them — the way in before sign-in links can be emailed, and how a person adds their first passkey then.",
      "body": {
        "name": "the staff member’s full name, as it will appear on every change they make",
        "role": "assessor | senior | compliance | admin | auditor",
        "email": "or: the work email of an active person on the lender’s staff list"
      }
    },
    "GET /v1/l/:tenant/cases?state=&ownership=&q=&flood=&page=&by=": {
      "what": "The work queue as the operations console shows it: open files first, those past their service level first, 25 a page. Needs that lender’s API key.",
      "query": {
        "state": "open | all | received | in review | waiting on applicant | concluded | withdrawn",
        "ownership": "all | unassigned | mine (mine needs by)",
        "q": "a reference, name, email, customer id or mobile",
        "flood": "1: only the files that look automated",
        "page": "from 1",
        "by": "optional: the work email of a person on the staff list, whose files are mine and who may close which"
      }
    },
    "GET /v1/l/:tenant/cases/:ref?by=": {
      "what": "One application’s case file as data: the applicant, the answers, the statement’s reading, the policy and score in shadow, verification, the ledger, the checklist, documents, notes, credit enquiries, the conclusion, the contract and the audit trail. Needs that lender’s API key.",
      "query": {
        "by": "optional: the work email of a person on the staff list, to say what they may do with the file now (for)"
      }
    },
    "POST /v1/l/:tenant/cases/:ref/actions": {
      "what": "One action on an application by a person on the staff list, through the console’s own checks: their role there decides, the event names them, and the case comes back as it stands. Each action and its fields are listed under actions in GET /v1/l. Needs that lender’s API key.",
      "body": "{action, by, seq?, …the action’s own fields}",
      "common": {
        "action": "the action, one of those listed",
        "by": "the work email of the person on the lender’s staff list who did it: their role there decides what they may do, and they are named on the event",
        "seq": "optional: the case’s seq as you read it; a case changed since is refused with 409. Required for a credit enquiry, which cannot be taken back"
      },
      "actions": {
        "take": {
          "what": "Take the file: the person holds it, and its figures are recorded from the rules.",
          "fields": {}
        },
        "release": {
          "what": "Let the file go, saying why.",
          "fields": {
            "reason": "why, so the next person knows where it stands"
          }
        },
        "reassign": {
          "what": "Give the file to another person on the staff list. A senior analyst or an operations admin.",
          "fields": {
            "to": "the work email of the person on the staff list who takes it",
            "reason": "why"
          }
        },
        "verify": {
          "what": "Record what was verified, keeping the earlier result beside it.",
          "fields": {
            "kind": "identity | contact | bank-name | centrelink",
            "status": "not started | pending | verified | mismatch | not required | failed | expired",
            "reason": "what was seen, and where",
            "provider": "optional",
            "reference": "optional"
          }
        },
        "item-verify": {
          "what": "Change a ledger row’s verified figure or next pay day.",
          "fields": {
            "id": "the row’s id",
            "verified": "dollars, a month (or the period the lender shows figures in)",
            "nextDate": "YYYY-MM-DD: an income’s next pay day",
            "reasonCode": "one of the lender’s adjustment reasons",
            "reasonText": "at most 500 characters",
            "evidence": "optional: what was seen"
          }
        },
        "item-add": {
          "what": "Add a ledger row the statement did not show.",
          "fields": {
            "type": "income | liability | expense",
            "category": "a category of that type",
            "label": "optional",
            "provider": "optional",
            "declared": "dollars, optional",
            "bank": "dollars, optional",
            "verified": "dollars",
            "frequency": "optional",
            "smallAmount": "true for a small amount credit contract",
            "nextDate": "YYYY-MM-DD, for income",
            "reasonCode": "one of the lender’s adjustment reasons",
            "reasonText": "at most 500 characters",
            "evidence": "optional"
          }
        },
        "item-remove": {
          "what": "Remove a ledger row; it stays on the file with the reason.",
          "fields": {
            "id": "the row’s id",
            "reasonCode": "one of the lender’s adjustment reasons",
            "reasonText": "at most 500 characters"
          }
        },
        "propose": {
          "what": "Record the proposed lending.",
          "fields": {
            "principal": "dollars",
            "termMonths": "months",
            "frequency": "weekly | fortnightly | monthly",
            "firstRepaymentOn": "YYYY-MM-DD"
          }
        },
        "snapshot": {
          "what": "Save the assessment snapshot a conclusion cites.",
          "fields": {}
        },
        "check": {
          "what": "Close, block or reopen a checklist item.",
          "fields": {
            "item": "the item’s key",
            "status": "done | not applicable | blocked | open",
            "note": "what was seen: needed to close it",
            "fromVersion": "optional: the item’s version as read, so a change made since is refused"
          }
        },
        "note": {
          "what": "Add a note: what happened, never a label for a person.",
          "fields": {
            "text": "at most 8,000 characters"
          }
        },
        "document-request": {
          "what": "Record a document asked of the applicant. Nothing is sent.",
          "fields": {
            "what": "which document",
            "why": "why it is needed",
            "due": "YYYY-MM-DD, optional"
          }
        },
        "document-received": {
          "what": "Mark a requested document received.",
          "fields": {
            "id": "the request’s id: doc-1, doc-2, …",
            "reason": "optional"
          }
        },
        "document-cancelled": {
          "what": "Cancel a document request, saying why.",
          "fields": {
            "id": "the request’s id",
            "reason": "why it is no longer needed"
          }
        },
        "document-check": {
          "what": "Record what checking a document against the file found.",
          "fields": {
            "id": "the request’s id",
            "result": "matches | does not match | unreadable",
            "note": "what was compared, and what was seen"
          }
        },
        "withdraw": {
          "what": "Close the file as withdrawn.",
          "fields": {
            "reason": "why; optional where the applicant withdrew or the application lapsed"
          }
        },
        "duplicate": {
          "what": "Close the file as a duplicate of the same applicant’s open application. Not a decision.",
          "fields": {
            "of": "the reference of the application it duplicates",
            "reason": "optional"
          }
        },
        "automated": {
          "what": "Close the file as an automated submission. Not a decision.",
          "fields": {
            "reason": "what showed it was automated"
          }
        },
        "conclude": {
          "what": "Record the conclusion with one of the lender’s reason codes, sealed.",
          "fields": {
            "reasonCode": "one of the lender’s reason codes",
            "rationale": "the evidence, figures and policy relied on: at least ten characters",
            "confirm": "true: the evidence, the changed figures, the checklist and the policy were reviewed"
          }
        },
        "confirm": {
          "what": "Confirm a conclusion waiting for a second check. Never by the person who concluded.",
          "fields": {
            "reason": "optional"
          }
        },
        "send-back": {
          "what": "Send a conclusion waiting for a second check back for more work.",
          "fields": {
            "reason": "why"
          }
        },
        "contract-details": {
          "what": "Record what a car, home or business loan’s contract names that the application could not ask, before it is prepared.",
          "fields": {
            "description": "car: year, make and model",
            "vin": "car: VIN or chassis number",
            "registration": "car: optional",
            "paidTo": "car: who is paid, optional",
            "address": "home: the property’s address",
            "title": "home: the title reference",
            "guarantors": "business: names, by commas"
          }
        },
        "prepare-contract": {
          "what": "Prepare the contract a standing not-unsuitable conclusion leads to.",
          "fields": {}
        },
        "ppsr": {
          "what": "Record a PPSR search, or the registration of a secured business loan’s security (equipment or an invoice), from the register’s receipt. Funding waits for the registration.",
          "fields": {
            "kind": "search | registration",
            "searchNumber": "search: the search number",
            "searchedOn": "search: YYYY-MM-DD, today or earlier; today if left out",
            "searchedBy": "search: abn | acn | serial",
            "value": "search: what was searched",
            "result": "search: clear | interests",
            "registrationNumber": "registration: the registration number",
            "registeredOn": "registration: YYYY-MM-DD, today or earlier; today if left out",
            "pmsi": "registration: true for a purchase-money security interest",
            "note": "optional"
          }
        },
        "contract-ended": {
          "what": "Record that the borrower ended the contract by written notice, before any money went.",
          "fields": {
            "endedOn": "YYYY-MM-DD: the day they told the lender, today or earlier",
            "how": "email, letter, message or other",
            "note": "optional"
          }
        },
        "funding-requested": {
          "what": "Record funding requested. A senior analyst only.",
          "fields": {
            "provider": "optional",
            "reference": "optional"
          }
        },
        "funded": {
          "what": "Record funding, from a settlement somebody has seen. A senior analyst only.",
          "fields": {
            "reference": "the provider’s or the bank’s reference for the payment",
            "provider": "optional",
            "settledOn": "YYYY-MM-DD, today or earlier; today if left out"
          }
        },
        "funding-failed": {
          "what": "Record that funding failed. A senior analyst only.",
          "fields": {
            "reason": "what failed",
            "provider": "optional",
            "reference": "optional"
          }
        },
        "payee-check": {
          "what": "Have the bank check the name on the account the advance is paid to. A senior analyst only.",
          "fields": {
            "bsb": "six digits",
            "account": "up to nine digits",
            "accountName": "as the bank holds it"
          }
        },
        "pay": {
          "what": "Pay the advance from the lender’s payments account. A senior analyst only.",
          "fields": {
            "bsb": "six digits",
            "account": "up to nine digits",
            "accountName": "as the bank holds it",
            "confirmClose": "true: the bank holds a different name, and the account is the borrower’s",
            "agreement": "true: ask for the repayments’ PayTo agreement on the same account"
          }
        },
        "payto-agreement": {
          "what": "Ask the borrower’s bank for a PayTo agreement for the repayments. A senior analyst only.",
          "fields": {
            "bsb": "six digits",
            "account": "up to nine digits",
            "accountName": "as the bank holds it"
          }
        },
        "payment-status": {
          "what": "Ask the payments provider where one of the loan’s payments stands. A senior analyst only.",
          "fields": {
            "instruction": "the payment’s instruction id"
          }
        },
        "payout-set-aside": {
          "what": "Set aside a payout the provider has no record of, so a new one can be made. A senior analyst only.",
          "fields": {
            "instruction": "the payout’s instruction id",
            "confirm": "true: the provider’s account shows no payment for it"
          }
        },
        "statement": {
          "what": "Add the bank’s CSV export, read as the application’s statement and assessed again; or put the other statement on file in use.",
          "fields": {
            "csv": "the CSV export, at most 2 MB",
            "filename": "optional",
            "use": "instead of csv: application | staff"
          }
        },
        "credit-enquiry": {
          "what": "Run a credit enquiry on the lender’s own agreement with a body. Needs seq.",
          "fields": {
            "body": "the credit reporting body"
          }
        },
        "credit-enquiry-record": {
          "what": "Record an enquiry made in a body’s own portal, with the report it gave. Needs seq.",
          "fields": {
            "body": "the credit reporting body",
            "on": "YYYY-MM-DD, the day it was made",
            "purpose": "what it was for",
            "outcome": "returned | no file",
            "receipt": "optional: the portal’s reference",
            "report": "{name, base64}: the report, a PDF or text, at most 640 KB"
          }
        }
      }
    },
    "GET /v1/l/:tenant/staff": {
      "what": "The lender’s staff list, as its Staff page shows it: each person with their id, work email, role and whether they are active — those who may be named in by — and the changes waiting for a second administrator. Needs that lender’s API key."
    },
    "POST /v1/l/:tenant/staff": {
      "what": "One change to the staff list, by an operations admin on it, under the Staff page’s own rules: nobody changes their own entry, the last administrator stays one, and a change that gives a senior analyst’s or an administrator’s role (or stops requiring a passkey) waits for a second administrator where there is one. Needs that lender’s API key.",
      "body": "{by, seq, op, …}: op is add | role | deactivate | reactivate | reset-passkeys | passkey-rule | approve | reject. add takes name, email, role; role takes id, role; deactivate, reactivate and reset-passkeys take id; passkey-rule takes roles ([] or [\"senior\"]); approve and reject take request. seq is the list’s, as read."
    },
    "POST /v1/l/:tenant/cases/close-automated": {
      "what": "Close files as automated submissions, up to 100 at once, as the queue does in a bot flood: each the person may close, at the seq it was read at; the rest listed with why. Needs that lender’s API key.",
      "body": {
        "by": "the work email of the person on the lender’s staff list who did it: their role there decides what they may do, and they are named on the event",
        "reason": "what showed they were automated",
        "applications": "[{ref, seq}]: each file, at the seq it was read at; at most 100"
      }
    },
    "POST /v1/l/:tenant/bank-connections": {
      "what": "Connect an applicant’s bank for your own application form. Send the applicant to url; they agree at their bank and come back to returnUrl with ?connection=<id>&status=ready|failed, and nothing personal. Their transactions are read by Creditcrest Statement exactly as on the hosted pages. Name the connection in the application, statement: {connection}: it is used once, before expiresAt, by whoever made it — you, with any of your own keys; with a sandbox key, that key alone. The connection is part of Statement and never charged on its own.",
      "body": {
        "applicant": "{firstName, lastName, email, mobile?}: email is needed, as the connection is made under it",
        "returnUrl": "https:// on a public host name, on your own site, where the applicant comes back to; any connection or status already in it is replaced",
        "test": "true for the provider’s own test bank, for a lender not yet live"
      }
    },
    "GET /v1/l/:tenant/bank-connections/:id": {
      "what": "Where a bank connection stands: pending, ready, failed (with why, in words the applicant may be shown), used (with the application) or expired, and expiresAt, until when it can be finished or used. Once read, a summary: the accounts read, the transactions and the days they cover, and whether the account holder’s name matches the applicant’s — never a transaction. While ready, figures: what the hosted finances screen shows the applicant from their bank, each figure a month with what it is made of, for your form to ask whether they look right; and shownHash, to send back with the application. Read it before trusting the status in the return address."
    },
    "GET /v1/l/:tenant/shadow": {
      "what": "A shadow report over the comparisons kept in your own records service, for a period of up to 92 days: agreement with your outcomes, the rules behind each difference, the figures, the score and what could not be read, sealed.",
      "query": {
        "from": "YYYY-MM-DD; 29 days before \"to\" if left out",
        "to": "YYYY-MM-DD; today in Sydney if left out"
      }
    }
  }
}