Valjean Specialty Documents API

Upload and download documents.

Operations 5

GET /submissions/{id}/documents Documents on a submission #
POST /submissions/{id}/documents Upload a document (up to 4 MB) #
POST /submissions/{id}/documents/complete Record a large upload #

Work with this as data

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-documents-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 Specification

valjeanspecialty-documents-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Valjean Specialty agent Documents 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: Documents
  description: Upload and download documents.
paths:
  /submissions/{id}/documents:
    get:
      operationId: listDocuments
      summary: Documents on a submission
      description: 'The file''s documents, plus the carrier paper you may have: presented quotes, binders, policies and endorsements.


        Any key (read or read-and-submit).'
      tags:
      - Documents
      x-valjean-scope: read
      security:
      - bearerAuth: []
      - apiKeyHeader: []
      - oauth2:
        - read
      parameters:
      - name: id
        in: path
        required: true
        description: Submission id.
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentList'
              example:
                documents:
                - id: 4186317b-232c-4da9-90a3-9f3b1fd9b7dc
                  source: file
                  kind: acord_125
                  file_name: ACORD 125.pdf
                  size_bytes: 182044
                  created_at: 2026-11-02 14:15:12+00:00
          headers:
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimitPolicy'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
      x-codeSamples:
      - lang: shell
        label: curl
        source: "curl -X GET \"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents\" \\\n  -H \"Authorization: Bearer $VALJEAN_KEY\""
      - lang: javascript
        label: Node
        source: "const res = await fetch(\"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents\", {\n  method: \"GET\",\n  headers: { Authorization: `Bearer ${process.env.VALJEAN_KEY}`, },\n});\nconsole.log(await res.json());"
      - lang: python
        label: Python
        source: "import os, requests\n\nres = requests.get(\n    \"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents\",\n    headers={\"Authorization\": f\"Bearer {os.environ['VALJEAN_KEY']}\"},\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
    post:
      operationId: uploadDocument
      summary: Upload a document (up to 4 MB)
      description: 'multipart/form-data with "file" and an optional "doc_type". Valjean reads it with AI and updates what''s needed. Over 4 MB: use an upload link.


        Needs a **read-and-submit** key and an agency with a signed broker agreement.'
      tags:
      - Documents
      x-valjean-scope: submit
      security:
      - bearerAuth: []
      - apiKeyHeader: []
      - oauth2:
        - submit
      parameters:
      - name: id
        in: path
        required: true
        description: Submission id.
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
              - file
              properties:
                file:
                  type: string
                  contentMediaType: application/octet-stream
                doc_type:
                  type: string
                  pattern: ^[a-z0-9_]{2,40}$
      responses:
        '201':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentCreated'
              example:
                document_id: 53a6ee6c-2017-4da0-83ab-e9703f6ff67e
                file_name: Loss runs 2021-2026.pdf
                doc_type: loss_runs
                note: Received. Valjean reads it and updates what's still needed in a minute or two.
          headers:
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimitPolicy'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '413':
          $ref: '#/components/responses/TooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedType'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
      x-codeSamples:
      - lang: shell
        label: curl
        source: "curl -X POST \"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents\" \\\n  -H \"Authorization: Bearer $VALJEAN_KEY\" \\\n  -F \"file=@loss-runs.pdf;type=application/pdf\""
      - lang: javascript
        label: Node
        source: "import fs from \"node:fs\";\n\nconst form = new FormData();\nform.append(\"file\", new Blob([await fs.promises.readFile(\"loss-runs.pdf\")], { type: \"application/pdf\" }), \"loss-runs.pdf\");\nconst res = await fetch(\"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents\", {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.VALJEAN_KEY}` },\n  body: form,\n});\nconsole.log(await res.json());"
      - lang: python
        label: Python
        source: "import os, requests\n\nres = requests.post(\n    \"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents\",\n    headers={\"Authorization\": f\"Bearer {os.environ['VALJEAN_KEY']}\"},\n    files={\"file\": (\"loss-runs.pdf\", open(\"loss-runs.pdf\", \"rb\"), \"application/pdf\")},\n)\nprint(res.json())"
      x-agentic-access:
        action: create
        consequence: Adds a document to the file.
        human_in_the_loop: A broker reviews it.
        reversible: 'Not by API: ask your broker to remove it.'
        confirm_with_user: true
  /submissions/{id}/documents/upload-url:
    post:
      operationId: getUploadLink
      summary: Get a link to upload a large file (up to 25 MB)
      description: 'A one-time link. PUT the file''s bytes to upload_url with the given Content-Type, then call /documents/complete.


        Needs a **read-and-submit** key and an agency with a signed broker agreement.'
      tags:
      - Documents
      x-valjean-scope: submit
      security:
      - bearerAuth: []
      - apiKeyHeader: []
      - oauth2:
        - submit
      parameters:
      - name: id
        in: path
        required: true
        description: Submission id.
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                file_name:
                  type: string
                  minLength: 1
                  maxLength: 200
                content_type:
                  type: string
                  minLength: 3
                  maxLength: 120
              required:
              - file_name
              - content_type
              additionalProperties: false
            example:
              file_name: SOV.xlsx
              content_type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UploadUrl'
          headers:
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimitPolicy'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '413':
          $ref: '#/components/responses/TooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedType'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
      x-codeSamples:
      - lang: shell
        label: curl
        source: "curl -X POST \"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents/upload-url\" \\\n  -H \"Authorization: Bearer $VALJEAN_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"file_name\":\"SOV.xlsx\",\"content_type\":\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"}'"
      - lang: javascript
        label: Node
        source: "const res = await fetch(\"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents/upload-url\", {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.VALJEAN_KEY}`, \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({\n    \"file_name\": \"SOV.xlsx\",\n    \"content_type\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"\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/agent/v1/submissions/SUBMISSION_ID/documents/upload-url\",\n    headers={\"Authorization\": f\"Bearer {os.environ['VALJEAN_KEY']}\"},\n    json={\n      \"file_name\": \"SOV.xlsx\",\n      \"content_type\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"\n    },\n)\nprint(res.json())"
      x-agentic-access:
        action: create
        consequence: Creates a one-time upload link; nothing is added until completeUpload.
        human_in_the_loop: None needed.
        reversible: Unused links expire.
        confirm_with_user: false
  /submissions/{id}/documents/complete:
    post:
      operationId: completeUpload
      summary: Record a large upload
      description: 'Call after PUTting the file to its upload link. Calling it twice returns the same document with duplicate: true.


        Needs a **read-and-submit** key and an agency with a signed broker agreement.'
      tags:
      - Documents
      x-valjean-scope: submit
      security:
      - bearerAuth: []
      - apiKeyHeader: []
      - oauth2:
        - submit
      parameters:
      - name: id
        in: path
        required: true
        description: Submission id.
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                upload_id:
                  type: string
                  pattern: ^[0-9a-f-]{36}-[\w.\-]{1,120}$
                file_name:
                  type: string
                  minLength: 1
                  maxLength: 200
                content_type:
                  type: string
                  minLength: 3
                  maxLength: 120
                doc_type:
                  type: string
                  pattern: ^[a-z0-9_]{2,40}$
              required:
              - upload_id
              - file_name
              - content_type
              additionalProperties: false
            example:
              upload_id: ed46fd9f-afa9-4f32-b134-5fb1abddcbdc-SOV.xlsx
              file_name: SOV.xlsx
              content_type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
      responses:
        '201':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentCreated'
          headers:
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimitPolicy'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '413':
          $ref: '#/components/responses/TooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedType'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
      x-codeSamples:
      - lang: shell
        label: curl
        source: "curl -X POST \"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents/complete\" \\\n  -H \"Authorization: Bearer $VALJEAN_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"upload_id\":\"ed46fd9f-afa9-4f32-b134-5fb1abddcbdc-SOV.xlsx\",\"file_name\":\"SOV.xlsx\",\"content_type\":\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"}'"
      - lang: javascript
        label: Node
        source: "const res = await fetch(\"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents/complete\", {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.VALJEAN_KEY}`, \"Content-Type\": \"application/json\" },\n  body: JSON.stringify({\n    \"upload_id\": \"ed46fd9f-afa9-4f32-b134-5fb1abddcbdc-SOV.xlsx\",\n    \"file_name\": \"SOV.xlsx\",\n    \"content_type\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"\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/agent/v1/submissions/SUBMISSION_ID/documents/complete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['VALJEAN_KEY']}\"},\n    json={\n      \"upload_id\": \"ed46fd9f-afa9-4f32-b134-5fb1abddcbdc-SOV.xlsx\",\n      \"file_name\": \"SOV.xlsx\",\n      \"content_type\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"\n    },\n)\nprint(res.json())"
      x-agentic-access:
        action: create
        consequence: Adds the uploaded document to the file.
        human_in_the_loop: A broker reviews it.
        reversible: 'Not by API: ask your broker to remove it.'
        confirm_with_user: true
  /submissions/{id}/documents/{docId}:
    get:
      operationId: getDocumentLink
      summary: Download a document
      description: 'A download link good for 5 minutes. Add ?redirect=1 to be redirected to the file instead. The link is a credential: don''t log or share it.


        Any key (read or read-and-submit).'
      tags:
      - Documents
      x-valjean-scope: read
      security:
      - bearerAuth: []
      - apiKeyHeader: []
      - oauth2:
        - read
      parameters:
      - name: id
        in: path
        required: true
        description: Submission id.
        schema:
          type: string
          format: uuid
      - name: docId
        in: path
        required: true
        description: Document id from the documents list.
        schema:
          type: string
          format: uuid
      - name: redirect
        in: query
        required: false
        description: 1 to be redirected (302) to the file instead of getting JSON.
        schema:
          type: string
          enum:
          - '1'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentLink'
          headers:
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimitPolicy'
        '302':
          description: 'With ?redirect=1: redirect to the file.'
          headers:
            Location:
              schema:
                type: string
                format: uri
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/ServerError'
      x-codeSamples:
      - lang: shell
        label: curl
        source: "curl -X GET \"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents/DOCUMENT_ID\" \\\n  -H \"Authorization: Bearer $VALJEAN_KEY\""
      - lang: javascript
        label: Node
        source: "const res = await fetch(\"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents/DOCUMENT_ID\", {\n  method: \"GET\",\n  headers: { Authorization: `Bearer ${process.env.VALJEAN_KEY}`, },\n});\nconsole.log(await res.json());"
      - lang: python
        label: Python
        source: "import os, requests\n\nres = requests.get(\n    \"https://api.valjeanspecialty.com/api/agent/v1/submissions/SUBMISSION_ID/documents/DOCUMENT_ID\",\n    headers={\"Authorization\": f\"Bearer {os.environ['VALJEAN_KEY']}\"},\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:
  responses:
    Forbidden:
      description: 'Not allowed: read_only (a read key tried to submit), agency_not_active (no signed broker agreement), not_offered (instant quotes are off), forbidden (API access off for the agency). Don''t retry.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: read_only
              message: This key can read only. Ask your Valjean broker for a key that can submit.
    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.
    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.
    Unauthorized:
      description: 'Key or token missing, wrong, expired or revoked (unauthorized). Don''t retry: get a new key or sign in again.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: unauthorized
              message: This API key isn't valid. Ask your Valjean broker for a new one.
    Conflict:
      description: 'The file''s state doesn''t allow it: closed, not_open, quote_expired, already_requested, not_withdrawable (the bind request already went to the market: call your broker), no_instant_market, limit, or ai_off (plain-sentence answers aren''t switched on; send answers by key). Don''t retry the same request.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: closed
              message: This submission is closed.
    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'
    ServerError:
      description: Something went wrong on Valjean's side (server_error). Safe to retry later; creates are idempotent with client_reference or an Idempotency-Key header.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: server_error
              message: Something went wrong. Try again shortly.
    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.
    UnsupportedType:
      description: 'File type not accepted (unsupported_type): PDF, images, Word, Excel, CSV or text.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: unsupported_type
              message: Send PDF, image, Word, Excel, CSV or text files.
  schemas:
    DocumentCreated:
      type: object
      properties:
        document_id:
          type: string
          format: uuid
        file_name:
          type: string
        doc_type:
          type: string
          description: Detected or given document type, e.g. acord_125, loss_runs, sov, other.
        note:
          type: string
        duplicate:
          type: boolean
          description: Only on /documents/complete when the upload was already recorded.
      required:
      - document_id
      - file_name
      - doc_type
    DocumentLink:
      type: object
      properties:
        file_name:
          type: string
        kind:
          type: string
        url:
          type: string
          description: 'Download link. It''s a credential: don''t log or share it.'
          format: uri
        expires_in_seconds:
          type: integer
      required:
      - file_name
      - kind
      - url
      - expires_in_seconds
    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
    Document:
      type: object
      properties:
        id:
          type: string
          format: uuid
        source:
          type: string
          description: '"file": the submission''s documents. "carrier": presented quotes, binders, policies, endorsements.'
          enum:
          - file
          - carrier
        kind:
          type: string
          description: Document type, or the carrier document kind (quote, binder, policy, endorsement).
        file_name:
          type: string
        size_bytes:
          type:
          - integer
          - 'null'
        created_at:
          type: string
          format: date-time
      required:
      - id
      - source
      - kind
      - file_name
      - size_bytes
      - created_at
    UploadUrl:
      type: object
      properties:
        upload_id:
          type: string
        upload_url:
          type: string
          description: PUT the file's bytes here.
          format: uri
        method:
          type: string
          const: PUT
        headers:
          type: object
          properties:
            Content-Type:
              type: string
          required:
          - Content-Type
        max_bytes:
          type: integer
        expires_in_seconds:
          type: integer
        then:
          type: string
          description: What to call next.
      required:
      - upload_id
      - upload_url
      - method
      - headers
      - max_bytes
      - expires_in_seconds
      - then
    DocumentList:
      type: object
      properties:
        documents:
          type: array
          items:
            $ref: '#/components/schemas/Document'
      required:
      - documents
  headers:
    RateLimitPolicy:
      description: 'The rate limit for this key, as an IETF RateLimit-Policy: 120 requests (q) per 60-second window (w), counted across all of Valjean''s servers. Over it, you get 429 with Retry-After.'
      schema:
        type: string
        example: '"per-key";q=120;w=60'
  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