Executive Summary: Cobalt Intelligence shipped a command-line interface for its Secretary of State, OFAC, UCC, and TIN verification stack. For alternative lending teams that prefer to consume KYB data through software rather than through a hosted dashboard, the CLI changes how the integration looks. This post walks through what each command surfaces, the workflow patterns the response shape supports, and where the CLI sits in the stack relative to credit decisioning. It is a technical evaluation for an engineering reader, not a how-to. No customer scenarios, no named borrowers; the response shapes shown are the ones the documented commands return.
What Is the Cobalt CLI, and Who Is It Built For?
The Cobalt CLI is an open-source Node.js package, distributed via npm as @cobaltintelligence/cli, that wraps Cobalt's Secretary of State data API and adjacent verification services in a single binary. It is built around five command groups: sos for Secretary of State business search, ofac for sanctions screening, tin for IRS Tax ID verification, full-verification (alias fv) for asynchronous 50-state runs, and auth and config for credential and settings management.
The intended consumer is an engineering team that already runs an underwriting pipeline and wants the KYB data surfaced inside that pipeline rather than inside a vendor's UI. For shops that consume verification through software, that is intake automation, application records, audit logging, and downstream financial underwriting handoff, a CLI removes the dashboard as a separate piece of infrastructure to integrate against.
What Problem Does a CLI Solve That a Hosted Dashboard Does Not?
Hosted KYB dashboards are good for the persona that lives inside them. An ops director who reviews flagged deals all day benefits from a UI built around that pattern. A compliance officer doing a quarterly audit benefits from a search interface that surfaces every flag in one place.
But the KYB layer at an alternative lender is consumed by software at least as much as by humans. Lead intake hits the system as a webhook. Application records live in a Salesforce-or-equivalent the team already paid to customize. The decision to advance or decline runs through a financial underwriting service that imports bank statement data, calculates daily balance, and applies the lender's risk model. None of that lives in a vendor's dashboard.
For that consumer, a hosted UI adds friction. A CLI returns a structured JSON envelope on stdout. The result fits cleanly into existing data paths, with no headless browser and no HTML parsing.
How Does the CLI Install and Authenticate?
Installation is a standard npm global with no native compilation step (~9 MB on disk).
npm install -g @cobaltintelligence/cli
cobalt auth login --key
cobalt auth status
# { "data": { "authenticated": true, "keyPreview": "...l2nq",
# "endpoint": "https://apigateway.cobaltintelligence.com" } }
The CLI accepts the API key three ways: --api-key flag, COBALT_API_KEY env var, or cobalt auth login. Env var is the right choice for CI and production workers. Two details: auth status masks the key to its last four characters in any structured response (so CI logs do not leak the credential), and pre-auth calls return a structured error envelope with an onboarding.human_action block. cobalt config path prints the platform-native config location when scripts need it.
What Does a Standard Secretary of State Verification Look Like?
A typical underwriting workflow at an alternative lender starts with confirming that a borrower exists, is in good standing, and has the operating tenure the application claims. The sos search subcommand returns all of this in a single call.
cobalt sos search "Example Business LLC" \
--state DE \
--screenshot --ucc --related \
-f json
The --state flag is required for live searches; the CLI also accepts --sos-id, --first-name, and --last-name as alternative search vectors. The -f json flag selects machine-readable output. The CLI also supports pretty and table for human-facing terminal use.
The response shape is the same across every state: SOS ID, entity type, current status, normalized status, filing date, principal address, registered agent, agent address, officer list (where the state discloses them), document list with direct PDF URLs, an optional screenshot URL, a confidence score, and a list of possibleAlternatives for fuzzy matches that did not score the highest. Status enums are normalized across states, so a Kentucky A - Active and a Delaware Active both map to normalizedStatus: "Active".
The CLI uses a small set of stable exit codes to indicate the outcome at the process level. Exit 0 is success, exit 4 is unauthenticated, exit 5 is bad request, and there are codes for rate limiting, timeouts, and unexpected errors. For CI scripts, the exit code is sufficient for the most common gate logic; the JSON body provides the structured detail when the script needs it. For the broader workflow argument on real-time SOS verification in alt-lending intake, Cobalt's earlier walkthrough on how real-time Secretary of State API verification prevents B2B credit application fraud covers the integration patterns that the CLI now wraps.
The Federal Reserve's 2025 Small Business Credit Survey reports that the share of small business owners applying at online lenders rose for the fifth consecutive year, while net satisfaction with online lenders fell from fifteen percent to two percent over the same window.[1] The combination, more applications and less trust, is the operational reality the KYB layer at an alternative lender has to absorb. Industry trade press tracking through 2025 documents the parallel growth in MCA-specific volume.[2]
How Does the Fuzzy Matcher Show Its Work?
A useful detail in the SOS response is the possibleAlternatives field. The matcher returns more than the top hit; it returns rejected candidates with their confidence scores. An underwriter or an auditor can see which other entities the system considered and at what confidence. A vendor that returns only the top hit asks the lender to trust the box. A vendor that returns the rejected candidates asks the lender to check the work. For audit defensibility, the second pattern is materially stronger.
How Should an Underwriter Use the Officer Array as a Fraud Signal?
The officers array in the response is more than a header field for the application file. Officer and registered-agent changes between application date and funding date are a documented fraud signal in alternative lending. A borrower who lists one set of officers at intake and a different set when the underwriter pulls a second verification five business days later has either restructured the entity (which warrants a conversation) or is masking the actual decision-makers (which warrants more than a conversation).
The integration pattern an MCA shop can build on top of this is a stored snapshot of the officers, agent name, and agent address at intake, paired with a re-pull of the same sos search at the moment of advance approval. A diff that shows any change to those three fields is a hard stop on the deal until the change is reconciled. The CLI returns the data in the same shape on every call, so the diff is a five-line implementation, not a project.
How Does the CLI Surface UCC Liens for Stacking Detection?
UCC-1 filings are the public record of secured-party interests in a business's collateral. For alternative lenders, particularly merchant cash advance funders and equipment lessors, the UCC search is the primary way to detect competing positions before underwriting a new advance. The Cobalt CLI surfaces UCC data as part of the same sos search call when the --ucc flag is passed.
UCC priority is first-to-file, first-to-perfect; understanding lien position before advancing is not a nice-to-have for a secured lender, it is the entire point of the search.[3] The mechanics of UCC perfection and the value of proactive monitoring are well-documented across the entity-services industry.[4]
Why Does the UCC Flag Matter for MCA Lenders Specifically?
Stacking, the practice of taking on multiple cash advances from different funders against the same receivables, is the most-flagged fraud vector in the merchant cash advance segment. The default-rate methodology debate inside the industry, well-documented in deBanked through 2025, makes the point that stacked deals carry meaningfully different repayment behavior than first-position advances, and that how a funder calculates default in the presence of stacking changes the answer.[5] Industry infrastructure is moving toward shared borrower-intelligence layers explicitly to address this; the 2025 launch of Ocrolus Encore is one example.[6]
For an MCA underwriting team, surfacing the UCC list inline with the SOS read means the stacking question is answered in the same call as the existence and status questions. No second integration, no second vendor, no second login. The structured envelope returns the active filings with secured-party names, filing dates, and filing identifiers. The lender's own logic decides whether the filings disqualify the deal, escalate it to ops review, or warrant a stack-check phone call.
The workflow pattern most MCA shops should be running on top of this is a tiered routing rule. Zero active UCC filings advances to financial underwriting automatically. One active filing from a non-MCA secured party (an equipment lessor, a working-capital line) advances with a flag, where "with a flag" operationally means a visible badge on the underwriter's screen, an entry in the audit log, and no second sign-off required (the secured party is non-competing). Any active filing from an identified MCA funder routes to an ops director queue for stack-check review before underwriting time is spent. The same envelope feeds all three branches; the routing logic, the badge surface, and any pricing impact are the lender's, not the vendor's.
How Does the CLI Handle OFAC and Sanctions Screening?
The ofac search subcommand screens a name against U.S. and international sanctions lists. The default coverage is all four list types: SDN (Specially Designated Nationals), NONSDN, SECO (Sectoral), and UN. Operators can narrow the source list with --sources SDN,NONSDN, restrict by entity type with -t organization|person|vessel|aircraft, tighten the fuzzy-match threshold with --score 95, and add address filters to reduce false positives.
cobalt ofac search "Example Business LLC" -f json
# {
# "data": { "name": "Example Business LLC",
# "matchCount": 0, "message": "No results found." },
# "meta": { "searchQuery": "Example Business LLC" }, "error": null
# }
A clean OFAC screen completes in under five seconds in standard usage; the surface is a list lookup, not a live web scrape, so the latency profile is much faster than a Secretary of State search. For real-time underwriting flows, this fits comfortably in the user-facing wait budget.
What Does Each of the Four Lists Cover?
The four-list default exists because each one captures a different slice of risk. SDN (Specially Designated Nationals) is the primary blocked-persons list maintained by Treasury OFAC; a hit on SDN typically means all transactions with the named party are prohibited under U.S. law. NONSDN covers narrower lists where the restriction is not a full block, such as the Foreign Sanctions Evaders List, the Sectoral Sanctions Identifications List, and the Non-SDN Communist Chinese Military Companies list. SECO (Sectoral Sanctions) captures restrictions that target specific sectors of a sanctioned country's economy, such as energy or finance, where the prohibition is on certain types of transactions rather than on the named entity in full. UN sanctions cover the United Nations Security Council Consolidated List, which most U.S. lenders are not legally bound to but most check anyway because international counterparties often are. For a non-bank lender screening domestic small businesses, SDN is the load-bearing list; the other three add coverage that costs almost nothing and rarely returns false positives.
How Should a Lender Tune the Fuzzy Match Threshold?
The --score flag accepts a value between 80 and 100, defaulting to 95. The tradeoff is straightforward: a higher score returns fewer matches but raises the false-negative risk; a lower score returns more matches but raises the false-positive rate that operations has to clear. For a name-only screen on a common entity name, a 95-default at the start of underwriting is reasonable, but a lender with a high-volume operation should benchmark the threshold against its own clearance data over the first ninety days and tune accordingly.
The address filter (--address, --city, --state, --postal-code) is the lever that earns the most. Pure name matching against SDN produces noise on common names; a name-plus-city filter reduces the false-positive rate substantially because the underlying SDN entries usually carry geographic detail. A Riyadh-listed sanctioned entity sharing a common Anglicized name with a Phoenix LLC will not clear the address filter, which means the underwriter never sees the false flag in the first place.
What Does the Response Look Like on a Possible Match?
A clean miss returns matchCount: 0 and a "No results found" message, as shown above. A possible match returns matchCount greater than zero with an array of matched entries, each carrying the source list (SDN, NONSDN, SECO, or UN), the matched entity name, the match score, and any address detail the list carries. For audit purposes, the lender should log the full response envelope in both cases, not just on hits. A clean screen six months ago is a defensible artifact only if the lender can prove the screen ran and what it returned at decision time.
What Does TIN Verification Surface?
The tin verify subcommand checks an EIN against IRS Tax ID Matching records, returning whether the TIN-and-name combination matches what the IRS has on file. The command surface is minimal:
cobalt tin verify --tin <9-digit-EIN> --name "Business Name as Filed"
The IRS TIN Matching Program, documented in IRS Publication 2108A, returns a small set of standardized numeric response codes that engineering teams in this segment use as terms of art.[7] Code 0 is the clean match (TIN and name align). Code 1 means the TIN was missing or not currently issued. Code 2 is the TIN-name mismatch (the TIN exists but does not pair with the submitted name). Code 3 is an invalid TIN (format failure). The remaining codes cover duplicate-request flags. For an MCA underwriting workflow, the binary that matters is Code 0 versus Code 2. A Code 2 is not by itself a decline, but it warrants a confirmation step with the borrower (the most common cause is a DBA name on the application that does not match the legal entity name on file with the IRS).
The TIN check is the smallest surface in the Cobalt CLI by design. It does what it does, returns the IRS code, and stays out of the way. The integration pattern is to wire it into the same envelope handler as the SOS read, log the result, and let the underwriter's screen show the binary in the same row as the OFAC clear stamp and the UCC summary.
How Does Full Verification Work for 50-State Runs?
For lenders that need broader coverage than a single-state SOS search, the full-verification (alias fv) command runs an asynchronous 50-state lookup. The pattern is start, then status, then optional wait or callback.
cobalt fv start --business-name "Example Business" -f json
# { "data": { "message": "Verification started",
# "searchGuid": "EXAMPLE BUSINESS#f2f7f931-..." } }
The start call returns immediately with a searchGuid. The expected production pattern is one of two paths. The first is webhook delivery via the --callback-url flag passed to start; the lender exposes an HTTPS endpoint that Cobalt posts the completed result to when the run finishes. This is the recommended path for production integrations because it removes the polling overhead from the lender's worker. The second is polling via cobalt fv status or the built-in cobalt fv wait helper, which polls at a default 15-second interval up to 120 attempts (a generous thirty-minute budget for a 50-state run).
cobalt fv start --business-name "Example Business" \
--callback-url "https://lender.example.com/cobalt/callback" \
-f json
For an alt-lender's worker queue, the --callback-url path is the cleaner integration: the worker that submitted the verification can return immediately, and a separate handler picks up the completed envelope when the callback fires. The searchGuid stays as the correlation ID across the application record, the worker submission, and the eventual callback. For ad-hoc CLI use during development, the wait subcommand is the convenient option.
How Can a Lender Build Compliance Evidence into Their Audit Trail?
Regulators and quarterly auditors want to see the work, not just the conclusion. The CLI's --screenshot flag captures a presigned S3 URL of the live Secretary of State page at the moment of verification. The URL has a fifteen-minute time-to-live, which means a production integration should fetch and re-host the image immediately to a long-term audit bucket; the CLI returns the URL once per verification.
The screenshot is paired with a documents array containing direct PDF URLs of every filing on record at the state's SOS site, when the state publishes those documents. For a 45-year-old corporation, that can be 30+ annual reports plus the original Articles of Incorporation, all linked to the canonical state source. The integration pattern most lenders should adopt is to fetch the screenshot and store the URLs of the documents (rather than re-hosting every PDF) into a write-once-read-many bucket scoped to the application record. The combined artifact is what an examiner sees six months later: image of the SOS page at decision time, plus the document trail as the state had it.
The compliance side of KYB has shifted under U.S. lenders. In March 2025, FinCEN issued an interim final rule that removed beneficial ownership information reporting requirements for U.S. companies and U.S. persons under the Corporate Transparency Act, while setting new deadlines for foreign companies.[8] The Federal Register text codified those revised deadlines and the harmonization language with existing CDD obligations.[9] That change does not eliminate the diligence floor; it relocates the burden onto the lender's own KYB process.
State-level enforcement has filled the gap. New York Department of Financial Services maintains an annual reporting regime for sales-based-financing providers that has become the de-facto disclosure benchmark in the segment.[10] On the federal side, the CFPB's 2025 Notice of Proposed Rulemaking under Regulation B Section 1071 explicitly examined whether MCA transactions should remain outside the covered set, demonstrating that federal policy on alt-lending oversight remains an active area of rulemaking.[11]
Why Does Audit-Defensible Evidence Matter More Now?
Stale state data and entity-law churn are the two structural risks the screenshot evidence is meant to mitigate. State SOS data can lag the actual entity state by six to eighteen months depending on the state's filing cadence, and entity-law changes through 2025 (covering DE, NV, TX, and several others) continue to affect what an SOS record discloses about agent of record and beneficial owner.[12] A screenshot taken at the moment of verification is the lender's defense against a question six months later: what did you see when you made the decision?
How Does Test Mode Make CI Integration Affordable?
Most paid verification APIs make CI integration expensive. Either the engineering team mocks the vendor's response shape themselves, building a parallel test layer that drifts from production, or they pay for live calls on every pull request. Cobalt's CLI ships a --test flag on the sos search command that returns the full production response shape without billing.
cobalt sos search "Test Business LLC" --test complete --state UT -f json
# Full prod-shape response: officers, agent, screenshot URL, possibleAlternatives. No charge.
cobalt sos search "Test Business LLC" --test failed --state UT -f json
# { "data": { "status": "Failed", "statusCode": 500,
# "message": "Error happened... You have not been charged." } }
cobalt sos search "Test Business LLC" --test badRequest --state UT -f json
# { "data": { "status": "Bad request", "statusCode": 400,
# "message": "searchQuery, sosId, or searchByPersonQuery is required" } }
The five test modes (complete, failed, incomplete, badRequest, retryIdInvalid) mirror the production envelope shapes for each scenario. The failed envelope explicitly returns the message "You have not been charged" inside the response body, mirroring the live behavior when an SOS lookup fails for reasons outside the lender's control. An engineering team can write integration tests against the same JSON envelope production returns, run them on every commit, and never burn a credit on a code-style change.
The deeper value of test mode is not just the CI savings; it is that the lender's own integration code never has to maintain a parallel mock layer. The shape an integration test asserts against in CI is the same shape production returns. There is no schema-drift class of bug because there is no second schema.
For long-running live calls, the CLI also persists a retryId to disk before billing the API. The pending file lives under the platform-native config directory in a pending/ subdirectory and is cleaned up automatically when the call completes successfully. If a worker dies mid-call, the file remains, and cobalt sos retry resumes the original verification without double-billing. The cobalt sos pending subcommand lists any retryIds currently persisted to disk, which is useful for an operations team that wants to surface stuck verifications in a dashboard. Together, the test mode and the retryId persistence describe a credit-safety model the CLI offers: not charged for failed lookups, not charged for unit-test integration, not charged twice for the same long-running call.
Where Does the CLI Sit in the KYB Stack for an MCA Shop?
The clearest way to think about Cobalt's place in an alternative lender's stack is as the ground-truth verification layer below the credit decision layer. The decision layer is where a lender's credit model lives, where the pricing engine lives, where the risk appetite is encoded. That layer differentiates one MCA shop from another, and most teams want to own it directly.
The KYB layer is not differentiation. Every alternative lender needs to know whether a borrower exists, whether the borrower is sanctioned, whether there are competing UCC liens, whether the EIN matches, and whether the officers and agent of record have changed since the application was first taken. That layer is plumbing. The right answer to plumbing is to buy it from a specialist, integrate it cleanly, and direct engineering budget to the parts of the stack that earn the spread. Middesk publishes a thorough KYB primer that lays out the typical vendor coverage model, including direct connections to SOS and IRS data sources, which can be a useful reference for teams sizing the landscape.[13]
The CLI form factor matters because plumbing has to be composable. A hosted dashboard is a destination; a CLI is a building block. The same KYB call has to feed intake automation, an underwriter's screen, a compliance audit log, a reconciliation queue, and quarterly board reporting. One JSON envelope, multiple consumers, one source of truth.
The line between "verification" and "decision" is the line a procurement-review CTO at an alternative lender should look for. A vendor that claims to make the credit decision is selling something more expensive than it can deliver; the credit decision needs bank statements, monthly revenue, daily balance, NSF history, and the lender's own model. A vendor that surfaces ground truth and hands the decision back is the layer worth owning. The throughput pressure is real: applications at online lenders have risen for five consecutive years per the 2025 Small Business Credit Survey, with no equivalent rise in lender headcount, which is the most direct argument for a cheap-and-fast verification layer at the top of the funnel.[14]
Pricing tiers and per-call rate limits are out of scope for this engineering evaluation; both belong in a procurement conversation with Cobalt's sales team and the current docs. The practical evaluation pattern for an engineering team is short. Start with --test complete to map the response shape against the application's existing data path. Wire the envelope into the same record the underwriter already reviews. Snapshot the officers and agent fields at intake and diff them against a re-pull at advance approval. Insist on test mode coverage. And read carefully for the line between "verification" and "decision" in any KYB vendor pitch; the layer that surfaces ground truth and hands the decision back is the layer worth owning.












.png)