Recommend Markets
Ask which markets fit a risk and get a ranked answer with the evidence, the resolution, and an honest account of what could not be assessed.
What this returns that browse does not
The rest of the catalog family is browse: you filter markets, products, or appetite cells and page through what matches. This endpoint answers a question instead. You describe a risk, in free text or in structured hints, and get back at most five markets in rank order, each with the evidence behind its position. It is synchronous and account-free. There is no run to submit, nothing to poll, and no account or prospect record involved. The resolution, the appetite gate, and the ordering are the same ones the placement engine applies internally, and this endpoint adds no judgment of its own on top of them: whether a market will write a class is decided in one place, by one piece of code, for both surfaces. Candidates are narrowed before the gate by the requested lines, a named excluded state, and the structured employee and premium bands. Nothing else narrows them. The free-text constraint columns are not interpreted here, because a value like “Nationwide” in an eligible-states list or “22 or more locations” in a prohibited-class list cannot be read with enough certainty to remove a market from a producer’s options. Use browse when you know what you are looking for. Use recommend when you have a risk and need to know where it can go.Asking the question
At least one ofq, naics, state, or lob must be present. Everything else is optional:
qis free text and is scanned for all three of state, line of business, and business class, soroofing contractor in Colorado needing general liabilityalone is a complete question.naicstakes a code at any grain. A code with no entry in the keyword bridge still resolves and is echoed back without a keyword rather than being dropped.stateacceptsCOorColorado.lobis repeatable and classified through the shared line taxonomy, so everyday phrasing works:lob=commercial propertyresolves to the codeproperty.employeesandpremium_band(estimated annual premium in whole US dollars) are used only for positive exclusion. A product is dropped when its own stated band excludes the value. A product that states no band is never dropped, because absent data is not a statement of ineligibility.
resolved, and names what it could not resolve
on missing_context (state, line_of_business, business_class). A partial question still gets
an answer built from the parts that did resolve; the caller decides whether the gap is worth a
clarifying question.
What verified each match
match_status says what actually stands behind a recommendation, and confidence is a
deterministic restatement of it rather than a separate score.
line_level_only result is a real answer, not a failure: it
says this market serves the line and nobody has recorded an appetite position on the class.
Reading the appetite block
appetite is present only when a current guide cell positively matched, and it is attributed to a
document. Two things follow from that, and both matter:
strength is the guide cell’s own eligibility word. It is not the product row’s served appetite
strength, and the two can disagree. When a product row says restricted and the guide cell says
acceptable, this block reports acceptable, because it is quoting the guide, not summarizing the
market. If you need the served value, read the product row through the browse endpoints.
line_code names which line the evidence covers. A market can come back with several products
while the cell speaks to one line. The line named here is always present in products, even when the
per-market product cap would otherwise have dropped it, so the claim is always checkable against a
row you were given. Do not read the appetite block as coverage of every product listed.
A market whose guide positively declined the resolved class and line is never recommended at all.
Only a known decline word excludes: an unknown, empty, or newly added eligibility leaves the market
in the answer as unassessed, because absence of a statement is not a decline.
Why a market ranks where it does
rank_reasons narrate only signals the ranking comparator actually read: appetite strength, then AM
Best rating, then pricing tier. It is a short array and it can be empty when the market’s best
offering carried none of them.
Appetite appears as a rank reason only when the line the cell matched is also the line that was
ranked, and the value the comparator read agrees with the cell. When it does not, the appetite is
still returned in the appetite block. It explains the match; it did not drive the position.
Product count is not a reason, and never will be: the comparator does not read it. The products
array itself shows the served lines in scope.
Commission never affects ordering. commission_new and commission_renewal are display-only
disclosed values. Nothing about the rank of a market is a function of what it pays.
What is never defaulted
am_best_ratingisnullwhen the corpus holds no rating. Null means not known. It is not “unrated”, and it is not a low rating.commission_newandcommission_renewalare omitted when the rate was never disclosed. An omitted rate is not a zero percent commission. Coalescing it to0will misrank a market in your own display and misinform a producer.staleis tri-state:true(assessed, out of date),false(assessed, current), and absent (never assessed). Absent andfalseare different facts. Treating absent asfalsepresents an unassessed schedule as verified-current.source_blob_refandextraction_run_idare omitted when lineage was not recorded. They are never fabricated.
When the answer is partial or empty
Two fields carry the limits of the answer, and they say different things.no_coverage carries the reason nothing could be answered: the query resolved to no class, line, or
state; the organization has no active catalog connection; or every requested line is outside this
catalog’s scope. It is also set when the class resolved but the corpus holds no appetite data for it,
and in that case markets are still listed by line and state and the message says so. Surface the
message; do not branch on its presence alone.
lines_not_assessed is a scope caveat that rides alongside results. This catalog serves commercial
lines and surety, while the taxonomy also resolves personal lines, so a mixed request is answered for
the lines in scope and told which ones were left out:
no_coverage is set too and
recommendations is empty.
Connections
Like the rest of the catalog family, the read is scoped to one data connection. Organizations with a single active connection can omitconnection_id; organizations with more than one must pass it, and
an ambiguous request returns catalog_connection_ambiguous with a 400. A connection_id that is not
an active connection for the organization returns 404 not_found rather than an empty answer, so a
pinned client that loses its connection fails loud. An organization with no active connection gets a
200 whose no_coverage says exactly that, rather than an answer that reads as “no market wants this”.
Example
am_best_rating as 0, or commission_new as 0%, would put a number in front of
a producer that no document ever stated.
Its rank_reasons also carry only one entry, because the comparator had only one signal to read on
it. That is the contract working: the array is a record of what was read, not a summary written after
the fact.
Authorizations
Send the credential as Authorization: Bearer <key>.
Scoped partner credentials use the exclusive nxsk_v1_... namespace.
Each scoped key is bound at issuance to one organization, one canonical
named environment, an explicit engine set, and a least-privilege
capability set. A malformed, unknown, rotated, or revoked nxsk_ key
fails closed and is never retried as a legacy key.
Capabilities used by this API are runs:write, runs:read,
engines:read, catalog:read, webhooks:manage,
runs:defensibility:read, runs:test, conversations:use, and
conversations:export. Operation descriptions name the required
capability.
Grandfathered nx_live_... and nx_test_... keys retain their existing
broad access during the compatibility window.
Query Parameters
Free-text description of the risk, for example roofing contractor in Colorado needing general liability. State, lines of business, and business class are all scanned out of it. At least one of q, naics, state, or lob must be present.
500NAICS business-class code, at any grain (23, 2381, 238160). A code with no entry in the keyword bridge still resolves and is echoed back with no keyword, rather than being dropped.
10US state as a two-letter code or a full name (CO and Colorado both resolve). Unresolvable text leaves resolved.state null and puts state in missing_context; it is not an error.
50Line of business, repeatable (?lob=general+liability&lob=workers+comp). Each value is classified through the shared line taxonomy, so both canonical codes and everyday phrasing work. At most 10 values, each at most 200 characters.
10200Applicant employee count. Used only for positive exclusion: a product is dropped when its own stated employee band excludes the number. Absent band data never excludes.
x >= 1Estimated annual premium in whole US dollars. Used only for positive exclusion against a product's stated premium band, the same way employees is used.
x >= 1Pin the browse to one active data connection. Optional when the org has a
single active connection; required when it has more than one (an ambiguous
request returns catalog_connection_ambiguous).
Response
The resolution, its corpus coverage, and up to 5 ranked markets.
A question the corpus cannot answer is still a 200: the honest
answer is the echo plus missing_context plus no_coverage, with
an empty recommendations array.
The request the answer was computed for, echoed back. Fields the caller did not send are omitted.
What the platform understood the query to mean. Same shape the taxonomy resolver serves.
Critical inputs the resolution could not supply, in a fixed order. The consumer decides whether to ask a clarifying question; the platform still answers with what it has.
state, line_of_business, business_class What the served corpus can actually answer for this resolution, including the honest zeroes.
Ranked markets, best first, at most 5. Always present; an empty array is the honest answer for a question with no matching market.
5Present when the corpus could answer nothing (the query resolved to no class, line, or state; the org has no active catalog connection; every requested line is outside this catalog's scope), and also when the class resolved but no served appetite data exists for it. In that last case markets are still listed by line and state, and the message says so. Read the message rather than branching on presence alone.
Requested lines this catalog could not assess, named in the labels the resolution produced. This catalog serves commercial lines and surety while the taxonomy also resolves personal lines, so a mixed request is answered for the lines in scope and this array says which ones were left out. It is a partial-scope caveat that rides alongside results, not a terminal state. When EVERY requested line is out of scope, no_coverage is set as well and recommendations is empty.