FlexPoint Docs
Engineering

Artisan Commands

Reference for every custom artisan command across the FlexPoint Portal API and the FlexRate pricing engine, with flags and when to run them.

Every first-party artisan command in the two Laravel services, grouped by purpose. Signatures are transcribed verbatim from each command's protected $signature.

Run from the right app root

flex-hub-api commands run from apps/flex-hub-api; flex-rate-api commands run from apps/flex-rate-api. Both are separately-deployed services with independent artisan binaries.

FlexPoint Portal API (apps/flex-hub-api)

Provisioning & identity sync

flexpoint:provision

Bootstrap a fresh instance: seed roles/notifications synchronously, then dispatch the MLM identity imports onto their priority queues. See the full Provisioning runbook.

php artisan flexpoint:provision --force
FlagEffect
--skip-mlmSeed identity + notifications only; do not dispatch MLM import jobs.
--forceRun without the production confirmation prompt (required in CI / non-interactive deploys).

mlm:sync-originating-companies

Sync originating companies from MLM into the portal database. Internally queues staggered ImportExternalUsers jobs for every company it discovers.

php artisan mlm:sync-originating-companies
FlagEffect
--nowRun the sync immediately instead of queueing it.

mlm:sync-internal-users

Sync internal (employee) users from MLM into the portal database.

php artisan mlm:sync-internal-users
FlagEffect
--email=*Only import the employee(s) with these exact email addresses (repeatable).
--nowRun the sync immediately instead of queueing it.

mlm:sync-external-users

Import external (PML) users from MLM for active originating companies.

php artisan mlm:sync-external-users
FlagEffect
--company=Only import users for the originating company with this index number.
--nowRun the imports immediately instead of queueing them.

MLM freshness

mlm:rehydrate-active-loans

Re-hydrate active imported loans from MeridianLink — the interim freshness sweep that keeps mapped fields and collections current without waiting on webhooks.

php artisan mlm:rehydrate-active-loans
FlagEffect
--loan=Only rehydrate the loan with this MLM number / reference.
--allInclude terminal-stage loans (funded / denied / withdrawn) too.
--stagger=5Seconds between successive queued jobs.
--nowRun the rehydrations immediately instead of queueing them.

mlm:resync-leads

Re-sync leads from MeridianLink — backfills multi-consumer ownership links and refreshes lead fields.

php artisan mlm:resync-leads
FlagEffect
--lead=Only resync the lead with this MLM number / reference / id.
--allInclude terminal-stage leads (funded / denied / withdrawn) too.
--stagger=5Seconds between successive queued jobs.
--nowRun the resyncs immediately instead of queueing them.

Discovery & audit

Live vendor calls

mlm:audit-loan, mlm:dump-collection, and mlm:probe-register hit MeridianLink under a real service ticket by default. Use --cached / --dry-run where available for read-only work, and never run the probe against a production loan.

mlm:audit-loan

Diff the LOS payload against the portal field maps to surface unmapped data — the machine answer to "is every data element imported?".

php artisan mlm:audit-loan <reference>
Argument / FlagEffect
referenceThe MLM loan number / reference (sLNm or sLRefNm).
--cachedDiff the stored snapshot instead of fetching a fresh one.
--jsonEmit the gap report as JSON.

mlm:audit-status-parity

Audit read + write parity for the in-scope MLM status/date fields (16 Key Dates + status): every field must have a MlmLoanFieldMap spec or a documented unmapped entry.

php artisan mlm:audit-status-parity

mlm:audit-visibility

Audit loan/lead visibility: how many grants rely on the vendor-number/ref backstop versus the stable FK.

php artisan mlm:audit-visibility
FlagEffect
--samples=10Max sample backstop-reliant rows to list per side.

mlm:dump-collection

Dump a MeridianLink LoadByRefNumber collection for a loan as JSON — the field mapping discovery helper.

php artisan mlm:dump-collection <loanNumber> <collection>
Argument / FlagEffect
loanNumberThe MLM loan reference number (sLRefNm).
collectionThe MLM collection id, e.g. Consumers, Assets, ConsumerAssetOwnerships.
--field=*Record field ids to request (repeatable). Defaults apply for known collections.
--out=Write the JSON to this path (relative to the app root) instead of stdout.

mlm:xml-to-json

Convert a MeridianLink LOXmlFormat loan XML file into a flat JSON object keyed by field id — for offline transform and fixture capture.

php artisan mlm:xml-to-json <path>
Argument / FlagEffect
pathPath to the LOXmlFormat XML file (relative to the app root or absolute).
--out=Write the JSON to this path instead of stdout.
--compactEmit minified JSON instead of pretty-printed.

mlm:probe-register

Live probe: register (and optionally lock) a program on a test loan and diff what MLM sets — used to reverse-engineer the rate-lock contract.

php artisan mlm:probe-register <loan> --dry-run
Argument / FlagEffect
loanMLM loan number / reference (sLNm or sLRefNm).
--ticket=Explicit MLM session ticket (else mints one from config creds).
--internalMint an internal-employee ticket instead of a broker (PML) ticket.
--program=Target program name (else the first eligible program from PriceMyLoan).
--template=Target lLpTemplateId (else the picked rate option template).
--rate=Target note rate, e.g. 6.99 (else the picked rate option rate).
--fee=requestedFee / points, e.g. -0.125 (else the picked rate option point).
--lockAlso call LockLoanProgram after a successful register.
--skip-dupUse the skip-duplicate-check register op (safe to re-run on a registered loan).
--listPrice the loan and print all eligible program/rate options, then exit.
--write-datesProbe finalize: write sRateLockStatusT=2 + sRLckdD + sRLckdExpiredD via Save, then diff.
--lock-days=30Lock period in days passed to register / lock.
--dry-runRead-only: mint ticket, price, and snapshot fields, but do not register/lock.

Maintenance & retention

mlm:prune-webhook-receipts

Delete MLM change-webhook receipts older than the retention window to keep the audit table bounded.

php artisan mlm:prune-webhook-receipts
FlagEffect
--days=7Delete receipts received more than this many days ago.

mlm:purge-document-bytes

Delete pre-downloaded MLM e-doc bytes (mlm-documents/) to reclaim disk; metadata and live streaming are unaffected.

php artisan mlm:purge-document-bytes --dry-run
FlagEffect
--dry-runReport what would be deleted without deleting anything.
--forceSkip the confirmation prompt.

Notifications & realtime

notifications:scan

Fire scheduled notification triggers for overdue loan conditions (loans with underwriting conditions past due and still unsatisfied).

php artisan notifications:scan

reverb:smoke

Post-deploy smoke test that verifies the Reverb WebSocket server is accepting connections. See Realtime (Laravel Reverb).

php artisan reverb:smoke
FlagEffect
--internalCheck the internal server bind instead of the public host.
--timeout=5Connection timeout in seconds.

FlexRate pricing engine (apps/flex-rate-api)

Rate-sheet extraction

Each extractor turns a lender's XLSX rate sheet into JSON. Defaults read from storage/app/incoming/<lender>-latest.xlsx and write to storage/app/rates/<lender>/.

rates:extract-flexpoint

Extract the FlexPoint Wholesale rate sheet xlsx into JSON per product tab.

php artisan rates:extract-flexpoint --pretty
FlagEffect
--file=Path to the FlexPoint rate sheet xlsx (default storage/app/incoming/flexpoint-latest.xlsx).
--out=Output directory (default storage/app/rates/flexpoint).
--prettyPretty-print the JSON output.

rates:extract-non-qm

Extract the Non-QM rate sheet xlsx into one JSON document per program (Full Doc, DSCR, Jumbo, …).

php artisan rates:extract-non-qm --pretty
FlagEffect
--file=Path to the Non-QM rate sheet xlsx (default storage/app/incoming/non-qm-latest.xlsx).
--out=Output directory (default storage/app/rates/non-qm).
--prettyPretty-print the JSON output.

rates:extract-silver-hill

Extract the Silver Hill rate sheet xlsx (Multi Property DSCR program) into JSON.

php artisan rates:extract-silver-hill --pretty
FlagEffect
--file=Path to the Silver Hill rate sheet xlsx (default storage/app/incoming/silver-hill-latest.xlsx).
--out=Output directory (default storage/app/rates/silver-hill).
--prettyPretty-print the JSON output.

Matrix PDFs

rates:matrix-fetch

Download the Non-QM matrix PDFs, cache raw pdftotext output, and write the fetch manifest (with SHA256 checksums).

php artisan rates:matrix-fetch
FlagEffect
--forceRe-download PDFs even when the local file already exists.
--dest=Override destination directory for downloaded PDFs.

rates:matrix-extract

Parse the fetched Non-QM matrix PDFs and write per-program eligibility JSON.

php artisan rates:matrix-extract --pretty
FlagEffect
--program=Extract only the named program slug.
--prettyPretty-print output JSON.

Daily orchestration

rates:daily

Run the full daily rate-sheet ingest: extract both xlsx files, fetch + parse the matrix PDFs, and reseed the rates database.

php artisan rates:daily
FlagEffect
--non-qm-file=Override path to the Non-QM xlsx.
--flexpoint-file=Override path to the FlexPoint xlsx.
--skip-matrixSkip matrix PDF fetch and extraction.

Parity harness

The parity harness proves FlexRate pricing matches MeridianLink across every program and LLPA dimension.

parity:generate-matrix

Generate the FlexRate ↔ MLM parity scenario matrix (the manifest of every MLM form submission needed to prove parity).

php artisan parity:generate-matrix
FlagEffect
--out=Override output path (default parity/scenarios/matrix.json).
--limit=Truncate the manifest to N scenarios (smoke testing).

parity:capture

Drive MLM through the parity matrix via the Playwright sidecar, writing captured observations to parity/observations/<run-id>/.

php artisan parity:capture --run-id=<id>
FlagEffect
--run-id=Run identifier; observations written to parity/observations/<run-id>/.
--authRun the one-time login helper instead of the capture loop.
--scenario=Run a single scenario by id (smoke testing).
--matrix=Override scenario manifest path (default parity/scenarios/matrix.json).
--limit=Process at most N scenarios this run (resumable).
--forceRe-capture scenarios whose output file already exists.
--headlessRun Chromium headless (default: visible window).
--fail-fastAbort the run on the first scenario failure.
--pause-after-fillFill the form then pause (keeps browser open for DevTools); does not submit.

parity:compare

Diff captured MLM observations against in-process FlexRate pricing and produce per-scenario diff reports.

php artisan parity:compare
FlagEffect
--run-id=Run ID (default: the most recent observations subdirectory).
--matrix=Path to scenario manifest (default parity/scenarios/matrix.json).
--tolerance=0.0001Pricing tolerance in points / price units.

parity:ingest-soap

Convert a BFP-API SOAP live-capture into a parity observation JSON.

php artisan parity:ingest-soap <scenario> <bfp_capture_dir>
Argument / FlagEffect
scenarioOur scenario id (e.g. pp-flexpoint-homeready).
bfp_capture_dirPath to the BFP API live-capture dir containing response.parsed.json.
--run-id=smokeOutput run id (default smoke).

Tooling

pricer:postman-export

Build a Postman v2.1 collection (and environment) from PHPUnit capture fixtures for manual API verification.

php artisan pricer:postman-export
FlagEffect
--source=Override capture directory (default tests/fixtures/postman/captured).
--out=Override output directory (default docs/postman).

On this page