Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/valjeanspecialty:valjeanspecialty-public-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Valjean Specialty agent Public API
version: 1.0.0
summary: Check appetite, send submissions, answer what's needed, follow files, get quotes and ask to bind.
description: 'For retail agencies'' own software and AI assistants. Every key sees only its own agency''s files. A named Valjean broker works every file: chooses the markets, confirms anything you send, presents quotes and completes binding. Market names appear only on quotes your broker presents.'
contact:
name: Valjean Specialty
email: submissions@valjeanspecialty.com
url: https://valjeanspecialty.com
license:
name: 'Proprietary: for Valjean Specialty agencies'
url: https://valjeanspecialty.com
x-mcp:
url: https://api.valjeanspecialty.com/api/mcp
transport: streamable-http
tools:
- whoami
- check_appetite
- get_requirements
- create_submission
- list_submissions
- get_submission
- answer_questions
- underwriter_questions
- add_document
- get_upload_link
- finish_upload
- send_documents
- whats_new
- list_documents
- get_document_link
- request_bind
- list_bind_requests
- withdraw_bind_request
- ask_instant_quotes
- list_policies
- get_policy
- list_invoices
- list_quotes
servers:
- url: https://api.valjeanspecialty.com/api/agent/v1
description: Live and demo (the key decides which book you see)
security:
- bearerAuth: []
- apiKeyHeader: []
- oauth2:
- read
tags:
- name: Public
description: 'No key needed: the website''s appetite check and class guides.'
paths:
/api/appetite:
post:
operationId: publicCheckAppetite
summary: Public appetite check (no key)
description: 'The same appetite answer without a key, for websites. Rate-limited to 30 requests a minute per IP; answers cache at the edge for 5 minutes. GET with the same fields as query parameters (lines comma-separated) also works.
No key needed.'
tags:
- Public
x-valjean-scope: public
servers:
- url: https://api.valjeanspecialty.com
description: Public endpoints (no key)
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
lines:
minItems: 1
maxItems: 6
type: array
items:
type: string
minLength: 1
maxLength: 60
state:
type: string
minLength: 2
maxLength: 40
naics:
type: string
pattern: ^[0-9]{2,6}$
description:
type: string
maxLength: 300
target_premium:
type: number
minimum: 0
maximum: 1000000000
tiv:
type: number
minimum: 0
maximum: 100000000000
required:
- lines
- state
additionalProperties: false
example:
lines:
- General Liability
state: South Carolina
description: restaurant with a bar
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/PublicAppetiteAnswer'
'400':
$ref: '#/components/responses/BadRequest'
'413':
$ref: '#/components/responses/TooLarge'
'429':
$ref: '#/components/responses/RateLimited'
x-codeSamples:
- lang: shell
label: curl
source: "curl -X POST \"https://api.valjeanspecialty.com/api/appetite\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"lines\":[\"General Liability\"],\"state\":\"South Carolina\",\"description\":\"restaurant with a bar\"}'"
- lang: javascript
label: Node
source: "const res = await fetch(\"https://api.valjeanspecialty.com/api/appetite\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n \"lines\": [\n \"General Liability\"\n ],\n \"state\": \"South Carolina\",\n \"description\": \"restaurant with a bar\"\n }),\n});\nconsole.log(await res.json());"
- lang: python
label: Python
source: "import os, requests\n\nres = requests.post(\n \"https://api.valjeanspecialty.com/api/appetite\",\n json={\n \"lines\": [\n \"General Liability\"\n ],\n \"state\": \"South Carolina\",\n \"description\": \"restaurant with a bar\"\n },\n)\nprint(res.json())"
x-agentic-access:
action: read
consequence: Reads only; changes nothing.
human_in_the_loop: None needed.
reversible: Nothing to undo.
confirm_with_user: false
get:
operationId: publicCheckAppetiteGet
summary: Public appetite check (no key), as a GET
description: 'Same as the POST form, with fields as query parameters; cacheable. lines is comma-separated.
No key needed.'
tags:
- Public
x-valjean-scope: public
servers:
- url: https://api.valjeanspecialty.com
description: Public endpoints (no key)
security: []
parameters:
- name: lines
in: query
required: true
schema:
minItems: 1
maxItems: 6
type: array
items:
type: string
minLength: 1
maxLength: 60
style: form
explode: false
description: Comma-separated.
- name: state
in: query
required: true
schema:
type: string
minLength: 2
maxLength: 40
- name: naics
in: query
required: false
schema:
type: string
pattern: ^[0-9]{2,6}$
- name: description
in: query
required: false
schema:
type: string
maxLength: 300
- name: target_premium
in: query
required: false
schema:
type: number
minimum: 0
maximum: 1000000000
- name: tiv
in: query
required: false
schema:
type: number
minimum: 0
maximum: 100000000000
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/PublicAppetiteAnswer'
'400':
$ref: '#/components/responses/BadRequest'
'429':
$ref: '#/components/responses/RateLimited'
x-codeSamples:
- lang: shell
label: curl
source: curl -X GET "https://api.valjeanspecialty.com/api/appetite"
- lang: javascript
label: Node
source: "const res = await fetch(\"https://api.valjeanspecialty.com/api/appetite\", {\n method: \"GET\",\n headers: { },\n});\nconsole.log(await res.json());"
- lang: python
label: Python
source: "import os, requests\n\nres = requests.get(\n \"https://api.valjeanspecialty.com/api/appetite\",\n)\nprint(res.json())"
x-agentic-access:
action: read
consequence: Reads only; changes nothing.
human_in_the_loop: None needed.
reversible: Nothing to undo.
confirm_with_user: false
/api/guides:
get:
operationId: listGuides
summary: Class guides (no key)
description: 'The classes Valjean publishes guidance for. Cached for an hour.
No key needed.'
tags:
- Public
x-valjean-scope: public
servers:
- url: https://api.valjeanspecialty.com
description: Public endpoints (no key)
security: []
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/GuideList'
'429':
$ref: '#/components/responses/RateLimited'
x-codeSamples:
- lang: shell
label: curl
source: curl -X GET "https://api.valjeanspecialty.com/api/guides"
- lang: javascript
label: Node
source: "const res = await fetch(\"https://api.valjeanspecialty.com/api/guides\", {\n method: \"GET\",\n headers: { },\n});\nconsole.log(await res.json());"
- lang: python
label: Python
source: "import os, requests\n\nres = requests.get(\n \"https://api.valjeanspecialty.com/api/guides\",\n)\nprint(res.json())"
x-agentic-access:
action: read
consequence: Reads only; changes nothing.
human_in_the_loop: None needed.
reversible: Nothing to undo.
confirm_with_user: false
/api/guides/{key}:
get:
operationId: getGuide
summary: One class guide (no key)
description: 'What Valjean needs for the class, with answer types, whether each item is confirmed with an underwriter, and a live appetite read for SC and GA.
No key needed.'
tags:
- Public
x-valjean-scope: public
servers:
- url: https://api.valjeanspecialty.com
description: Public endpoints (no key)
security: []
parameters:
- name: key
in: path
required: true
description: Guide key, e.g. gl_hospitality.
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/Guide'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/RateLimited'
x-codeSamples:
- lang: shell
label: curl
source: curl -X GET "https://api.valjeanspecialty.com/api/guides/gl_hospitality"
- lang: javascript
label: Node
source: "const res = await fetch(\"https://api.valjeanspecialty.com/api/guides/gl_hospitality\", {\n method: \"GET\",\n headers: { },\n});\nconsole.log(await res.json());"
- lang: python
label: Python
source: "import os, requests\n\nres = requests.get(\n \"https://api.valjeanspecialty.com/api/guides/gl_hospitality\",\n)\nprint(res.json())"
x-agentic-access:
action: read
consequence: Reads only; changes nothing.
human_in_the_loop: None needed.
reversible: Nothing to undo.
confirm_with_user: false
components:
schemas:
AnswerSpec:
type: object
properties:
type:
type: string
description: How to answer. "file" means upload a document instead.
enum:
- text
- number
- money
- percent
- yes_no
- choice
- date
- file
options:
type: array
items:
type: string
description: 'For type "choice": the allowed answers.'
required:
- type
AppetiteAnswer:
type: object
properties:
fit:
type: string
description: '"unknown" means no appetite is on file for these lines yet: fall back to your own guidance.'
enum:
- good
- possible
- unlikely
- unknown
appetite_on_file:
type: boolean
headline:
type: string
description: One sentence you can show as is.
market_count:
type: integer
description: Markets on file that could write it, capped at 5. Market names are never returned.
market_count_label:
type: string
description: e.g. "2 markets", "5+ markets", "Not on file yet".
lines:
type: array
items:
type: object
properties:
line:
type: string
description: Line code.
fit:
type: string
enum:
- good
- possible
- unlikely
required:
- line
- fit
notes:
type: array
items:
type: string
needs:
type: array
items:
type: string
description: What Valjean will need for this risk, in plain words.
class_matched:
type:
- string
- 'null'
description: The class Valjean matched the risk to, if any.
state:
type: string
description: Two-letter state code.
unknown_lines:
type: array
items:
type: string
description: Lines in the request Valjean didn't recognise.
how_to_send:
$ref: '#/components/schemas/HowToSend'
required:
- fit
- appetite_on_file
- headline
- market_count
- market_count_label
- lines
- notes
- needs
- class_matched
- state
GuideSummary:
type: object
properties:
key:
type: string
name:
type: string
class:
type: string
line:
type: string
line_name:
type: string
naics_prefixes:
type: array
items:
type: string
keywords:
type: array
items:
type: string
required:
- key
- name
- class
- line
- line_name
- naics_prefixes
- keywords
HowToSend:
type: object
properties:
email:
type: string
description: Where to email the risk instead.
format: email
include:
type: array
items:
type: string
description: What to include in that email.
note:
type: string
required:
- email
- include
- note
description: 'Present whenever the fit isn''t "good": a broker reviews every submission, including ones outside the appetite on file.'
Error:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: Machine-readable code, e.g. invalid_request, read_only, not_found, closed, rate_limited.
message:
type: string
description: Plain-English explanation you can show a person.
issues:
type: array
items:
type: string
description: 'Validation problems, as "field: problem" (400 invalid_request only).'
required:
- code
- message
required:
- error
Guide:
allOf:
- $ref: '#/components/schemas/GuideSummary'
- type: object
properties:
updated_at:
type: string
format: date-time
appetite:
type: array
items:
type: object
properties:
state:
type: string
fit:
type: string
enum:
- good
- possible
- unlikely
- unknown
headline:
type: string
market_count_label:
type: string
required:
- state
- fit
- headline
- market_count_label
needs:
type: array
items:
type: object
properties:
key:
type: string
label:
type: string
level:
type: string
enum:
- required
- sometimes
- helpful
kind:
type: string
answer:
$ref: '#/components/schemas/AnswerSpec'
help:
type:
- string
- 'null'
confirmed:
type: boolean
description: 'False: Valjean''s typical list, not yet confirmed with an underwriter; say "typically".'
required:
- key
- label
- level
- kind
- answer
- help
- confirmed
disclaimer:
type: string
required:
- updated_at
- appetite
- needs
- disclaimer
PublicAppetiteAnswer:
allOf:
- $ref: '#/components/schemas/AppetiteAnswer'
- type: object
properties:
disclaimer:
type: string
required:
- disclaimer
GuideList:
type: object
properties:
guides:
type: array
items:
$ref: '#/components/schemas/GuideSummary'
required:
- guides
responses:
NotFound:
description: Not found, or not your agency's (not_found). The API never says which.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: not_found
message: Submission not found.
BadRequest:
description: Fix the request and send it again (invalid_request, invalid_json).
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: invalid_request
message: Check the request.
issues:
- 'insured.state: Too small: expected string to have >=2 characters'
TooLarge:
description: 'Body or file too large (too_large): JSON bodies up to 64 KB, direct uploads 4 MB, upload links 25 MB.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: too_large
message: Files over 4 MB need an upload link.
RateLimited:
description: 'Too many requests (rate_limited): 120 a minute per key, 30 a minute per IP on public endpoints, counted across all of Valjean''s servers. Wait Retry-After seconds.'
headers:
Retry-After:
description: Seconds to wait.
schema:
type: integer
example: 60
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error:
code: rate_limited
message: Too many requests. Try again in a minute.
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: vjk_live_… / vjk_demo_… API key, or an OAuth access token (vjat_…)
description: 'Send the key as `Authorization: Bearer vjk_…`. Keys come from your agency portal or your Valjean broker.'
apiKeyHeader:
type: apiKey
in: header
name: X-Api-Key
description: The same API key in an X-Api-Key header, for tools that can't set Authorization.
oauth2:
type: oauth2
description: 'For AI apps that connect by signing in. Authorization code flow with PKCE (S256 only), public clients (no secret), dynamic client registration at https://api.valjeanspecialty.com/oauth/register. Discovery: https://api.valjeanspecialty.com/.well-known/oauth-authorization-server. Access tokens last 1 hour; refresh tokens 30 days and rotate on use. Tokens stop when the API key or portal link that approved them is revoked.'
flows:
authorizationCode:
authorizationUrl: https://api.valjeanspecialty.com/oauth/authorize
tokenUrl: https://api.valjeanspecialty.com/oauth/token
refreshUrl: https://api.valjeanspecialty.com/oauth/token
scopes:
read: Appetite, requirements, status, quotes, documents, policies
submit: Also send files, answers, documents, bind requests and instant-quote asks
x-event-types:
- submission.received
- submission.status_changed
- needs.requested
- markets.updated
- quote.presented
- bind.status_changed
- policy.bound
- policy.status_changed
- document.available
- invoice.sent
- invoice.paid
- invoice.overdue