Plain Insurance MCP
An MCP server for Plain Insurance that allows AI assistants to discover business insurance products, collect company details like CVR, and retrieve live indicative quotes for Danish companies without requiring an account or API key for the quoting phase.
Endpoint and access
No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.
https://app.plain.insurance/api/mcpWhat its tools do
8 tools, grouped by the hints the server advertises. Hints are self-declared, not verified behavior.
Checks and signals
Each line is separate evidence, not a trust score.
- Passed Endpoint answered the live check ·
- Passed Official MCP Registry namespace is tied to plain.insurance ·
- Passed Endpoint is on the registry namespace domain ·
- Availability 1 of 1 checks passed in 30 days
What you can do with it
- Discover suitable business insurance products for a Danish company
- Collect required company answers and product questions
- Retrieve live indicative prices and quotes
- Prepare unsigned offers for customer review
Source and maintenance
Protocol and capabilities
- Server
- plain 1.0.0
- MCP protocol negotiated in check
- 2025-11-25
- Tools
- 8 advertised
- Resources
- Not advertised
- Resource templates
- Not advertised
- Prompts
- Not advertised
{
"tools": {
"listChanged": true
}
}Tools
8 advertised
list_onboarding_catalog — List products and questions
Lists the insurance products a Danish company can be offered and the questions to answer before quoting. Pass the company's CVR to resolve industry-specific questions and options. Use product slugs in `products` and question names as keys in `answers`. Employee FTE questions are listed as two whole-number questions, `<name>.fullTime` and `<name>.partTime`, each from 0 to 9999 inclusive; when required, send both counts, including zero. Numeric questions publish min/max limits when configured. Products with automaticQuote:false need manual review and list no questions. A product's requiredProducts must be selected with it; its questions include theirs. MultiSelect answers may be left out and default to an empty list. Enum fields use {value, label: {da, en}}; use value for logic and label for display. Read-only: nothing is created. Works without signing in. For an existing customer, call list_companies first and select the company with set_company_context. Use its CVR when collecting questions and quoting.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {
"cvr": {
"type": "string",
"pattern": "^[0-9]{8}$",
"description": "Danish company registration number (CVR), eight digits, e.g. 39488914."
},
"region": {
"type": "string",
"const": "dk",
"default": "dk",
"description": "Market. Only Denmark (dk) is supported. Optional; defaults to dk."
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"products",
"productDependencies",
"errors"
],
"properties": {
"errors": {
"type": "array",
"items": {
"type": "object",
"required": [
"code",
"message",
"nextAction"
],
"properties": {
"max": {
"anyOf": [
{
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
{
"type": "number"
}
],
"description": "Inclusive maximum: the latest start date (YYYY-MM-DD) for invalid_start_date, or the numeric upper bound for invalid_answer."
},
"min": {
"anyOf": [
{
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
{
"type": "number"
}
],
"description": "Inclusive minimum: the earliest start date (YYYY-MM-DD) for invalid_start_date, or the numeric lower bound for invalid_answer."
},
"code": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"invalid_answer",
"missing_answer",
"ambiguous_question",
"invalid_start_date",
"cvr_not_found",
"invalid_products",
"missing_product",
"invalid_request",
"request_too_large",
"unsupported_media_type",
"wrong_identity_mode",
"idempotency_key_mismatch",
"idempotency_conflict",
"price_changed",
"invalid_partner_code",
"invalid_verification",
"sign_in_required",
"onboarding_expired",
"not_authenticated",
"not_authorized",
"consent_required",
"temporarily_unavailable",
"invalid_backend_response",
"rate_limited",
"operation_in_progress",
"price_unavailable",
"manual_review_required",
"pricing_configuration",
"unsupported_input",
"unexpected_error",
"not_found"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"not_found": {
"da": "Ikke fundet",
"en": "Not found"
},
"rate_limited": {
"da": "For mange forespørgsler",
"en": "Too many requests"
},
"cvr_not_found": {
"da": "CVR-nummer ikke fundet",
"en": "CVR number not found"
},
"price_changed": {
"da": "Prisen er ændret",
"en": "Price changed"
},
"invalid_answer": {
"da": "Ugyldigt svar",
"en": "Invalid answer"
},
"missing_answer": {
"da": "Svar mangler",
"en": "Missing answer"
},
"not_authorized": {
"da": "Ingen adgang",
"en": "Not authorized"
},
"invalid_request": {
"da": "Ugyldig forespørgsel",
"en": "Invalid request"
},
"missing_product": {
"da": "Påkrævet produkt mangler",
"en": "Required product missing"
},
"consent_required": {
"da": "Samtykke påkrævet",
"en": "Consent required"
},
"invalid_products": {
"da": "Ugyldige produkter",
"en": "Invalid products"
},
"sign_in_required": {
"da": "Login påkrævet",
"en": "Sign-in required"
},
"unexpected_error": {
"da": "Uventet fejl",
"en": "Unexpected error"
},
"not_authenticated": {
"da": "Ikke logget ind",
"en": "Not signed in"
},
"price_unavailable": {
"da": "Prisen kan ikke beregnes",
"en": "Price unavailable"
},
"request_too_large": {
"da": "Forespørgslen er for stor",
"en": "Request too large"
},
"unsupported_input": {
"da": "Oplysningerne understøttes ikke",
"en": "Unsupported input"
},
"ambiguous_question": {
"da": "Spørgsmålet er ikke entydigt",
"en": "Ambiguous question"
},
"invalid_start_date": {
"da": "Ugyldig startdato",
"en": "Invalid start date"
},
"onboarding_expired": {
"da": "Tilmeldingen er udløbet",
"en": "Signup expired"
},
"wrong_identity_mode": {
"da": "Forkert godkendelsesmetode",
"en": "Wrong authentication method"
},
"idempotency_conflict": {
"da": "Idempotensnøglen er allerede brugt til andre oplysninger",
"en": "Idempotency key already used for different input"
},
"invalid_partner_code": {
"da": "Ugyldig partnerkode",
"en": "Invalid partner code"
},
"invalid_verification": {
"da": "Ugyldig eller udløbet bekræftelseskode",
"en": "Invalid or expired verification code"
},
"operation_in_progress": {
"da": "Handlingen er i gang",
"en": "Operation in progress"
},
"pricing_configuration": {
"da": "Prisopsætningen skal gennemgås",
"en": "Pricing configuration needs review"
},
"manual_review_required": {
"da": "Individuelt tilbud påkrævet",
"en": "Individual offer required"
},
"unsupported_media_type": {
"da": "Indholdstypen understøttes ikke",
"en": "Unsupported media type"
},
"temporarily_unavailable": {
"da": "Midlertidigt utilgængelig",
"en": "Temporarily unavailable"
},
"idempotency_key_mismatch": {
"da": "Idempotensnøglerne er forskellige",
"en": "Idempotency keys do not match"
},
"invalid_backend_response": {
"da": "Ugyldigt svar fra serveren",
"en": "Invalid backend response"
}
}
}
},
"description": "Error code and its translated labels.",
"additionalProperties": false
},
"field": {
"type": "string",
"description": "Request field to correct, using dot notation for nested fields."
},
"reason": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"industry_not_covered",
"unknown"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"unknown": {
"da": "Ukendt årsag",
"en": "Unknown reason"
},
"industry_not_covered": {
"da": "Branchen er ikke dækket",
"en": "Industry not covered"
}
}
}
},
"description": "For price_unavailable: industry_not_covered when the product has no tariff for the company's industry, otherwise unknown.",
"additionalProperties": false
},
"message": {
"type": "string",
"description": "Human-readable explanation in English."
},
"product": {
"type": "string",
"description": "Slug of the product the error concerns, when it concerns one."
},
"question": {
"type": "string",
"description": "Answer key of the question the error concerns, as used in `answers`."
},
"didYouMean": {
"type": "string",
"description": "Suggested catalog product slug or answer key. Retry only after confirming the intended value."
},
"nextAction": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"fixAnswer",
"askUser",
"retryLater",
"contactPlain",
"none"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"none": {
"da": "Ingen handling nødvendig",
"en": "No action needed"
},
"askUser": {
"da": "Bed kunden om oplysninger eller login",
"en": "Ask the customer for input or to sign in"
},
"fixAnswer": {
"da": "Ret oplysningerne og prøv igen",
"en": "Correct the request and try again"
},
"retryLater": {
"da": "Prøv igen senere",
"en": "Try again later"
},
"contactPlain": {
"da": "Kontakt Plain",
"en": "Contact Plain"
}
}
}
},
"description": "What to do next: fixAnswer (correct the request and retry), askUser (ask the person for new input or to sign in), retryLater (retry the same request later), contactPlain (Plain must review this case; refer the person to Plain), none (nothing to do).",
"additionalProperties": false
},
"allowedValues": {
"type": "array",
"items": {
"type": "string"
},
"description": "For invalid_answer on a select question: the option keys that are accepted."
},
"questionLabel": {
"type": "object",
"required": [
"da"
],
"properties": {
"da": {
"type": "string",
"description": "Danish question label from the catalog."
}
},
"description": "Danish question label, when the question can be identified in the catalog.",
"additionalProperties": false
}
},
"description": "One problem with a request.",
"additionalProperties": false
},
"description": "Products that are listed but cannot currently be quoted, e.g. pricing_configuration."
},
"products": {
"type": "array",
"items": {
"type": "object",
"required": [
"product",
"name",
"description",
"coverage",
"termsUrl",
"termsDocuments",
"region",
"currency",
"billingFrequency",
"automaticQuote",
"pricePerEmployee",
"requiredProducts",
"questions"
],
"properties": {
"name": {
"type": "string",
"description": "Product name in Danish."
},
"region": {
"type": "string",
"description": "Market of the product: dk."
},
"product": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"maxLength": 100,
"description": "Product slug. Use it in `products` and to qualify answer keys."
},
"coverage": {
"type": [
"string",
"null"
],
"description": "What the insurance covers, in Danish."
},
"currency": {
"type": "string",
"description": "ISO 4217 currency of all prices for this product: DKK."
},
"termsUrl": {
"type": [
"string",
"null"
],
"description": "Link to the full insurance terms as PDF. Same as `termsDocuments.termsPdf`."
},
"questions": {
"type": "array",
"items": {
"type": "object",
"required": [
"question",
"required"
],
"properties": {
"question": {
"type": "object",
"required": [
"name",
"title",
"description",
"type"
],
"properties": {
"max": {
"type": "number",
"description": "Inclusive maximum numeric answer, when configured. Employee counts have a maximum of 9999."
},
"min": {
"type": "number",
"description": "Inclusive minimum numeric answer, when configured. Employee counts have a minimum of 0."
},
"name": {
"type": "string",
"description": "Answer key: use it as the key in `answers`."
},
"step": {
"type": "number",
"description": "Suggested numeric input increment, when configured. Employee counts use 1 (whole numbers)."
},
"type": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"Text",
"NumberWhole",
"NumberDecimal",
"Date",
"Boolean",
"Select",
"MultiSelect"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"Date": {
"da": "Dato",
"en": "Date"
},
"Text": {
"da": "Tekst",
"en": "Text"
},
"Select": {
"da": "Vælg én",
"en": "Select one"
},
"Boolean": {
"da": "Ja eller nej",
"en": "Yes or no"
},
"MultiSelect": {
"da": "Vælg flere",
"en": "Select multiple"
},
"NumberWhole": {
"da": "Heltal",
"en": "Whole number"
},
"NumberDecimal": {
"da": "Decimaltal",
"en": "Decimal number"
}
}
}
},
"description": "Answer type: Text, NumberWhole (integer), NumberDecimal, Date (YYYY-MM-DD), Boolean, Select (one key of `options`) or MultiSelect (array of keys).",
"additionalProperties": false
},
"unit": {
"type": "string",
"description": "Answer unit from the question's unit setting, when configured."
},
"title": {
"type": [
"string",
"null"
],
"description": "The question as shown to the customer, in Danish."
},
"period": {
"type": "string",
"description": "Answer period from the question's period setting, when configured."
},
"options": {
"type": "array",
"items": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da"
],
"properties": {
"da": {
"type": "string",
"description": "Danish option label from the backend."
}
},
"description": "Localized option label. Currently only Danish is available.",
"additionalProperties": false
},
"value": {
"type": "string",
"description": "Option value to send as the answer."
}
},
"additionalProperties": false
},
"minItems": 1,
"description": "Available options in display order. Omitted when there are none. Answer with `value`, not the label."
},
"description": {
"type": [
"string",
"null"
],
"description": "Help text in Danish."
}
},
"description": "A question to answer before pricing.",
"additionalProperties": false
},
"required": {
"type": "boolean",
"description": "Whether the product cannot be priced without this answer."
}
},
"description": "A question for this product and whether its answer is required.",
"additionalProperties": false
},
"description": "Questions to answer for this product, including company-wide questions shared with other products and the questions of its `requiredProducts`. Empty when automaticQuote is false."
},
"description": {
"type": [
"string",
"null"
],
"description": "Short product description in Danish."
},
"insuranceId": {
"type": [
"string",
"null"
],
"description": "Original insurance ID for matching existing content product references. Use the product slug, not this ID, when quoting."
},
"automaticQuote": {
"type": "boolean",
"description": "Whether this product supports an instant quote. False means manual review is required: its questions are not listed and the quote returns contactPlain without answers. True does not guarantee a price for every company or set of answers."
},
"termsDocuments": {
"anyOf": [
{
"type": "object",
"required": [
"termsPdf",
"ipidPdf",
"ipidYaml",
"termsMarkdown"
],
"properties": {
"ipidPdf": {
"type": "string",
"description": "Insurance product information document (IPID) as PDF. Give this link to the customer."
},
"ipidYaml": {
"type": "string",
"description": "The IPID as YAML, for agents to read the key facts: what is and is not covered, restrictions and obligations."
},
"termsPdf": {
"type": "string",
"description": "Full insurance terms as PDF. Give this link to the customer."
},
"termsMarkdown": {
"type": "string",
"description": "Full insurance terms as Markdown, for agents to read and answer questions about coverage."
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Links to the product's terms documents, or null when it has none. Read the YAML and Markdown to answer questions; give the customer the PDF links. External terms use the same link for all four."
},
"billingFrequency": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"Monthly",
"Annual"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"Annual": {
"da": "Årlig",
"en": "Annual"
},
"Monthly": {
"da": "Månedlig",
"en": "Monthly"
}
}
}
},
"description": "How often the customer pays: Monthly or Annual. Prices are per period of this frequency.",
"additionalProperties": false
},
"pricePerEmployee": {
"type": "boolean",
"description": "Whether the quoted price is per covered employee. The employees are selected when purchasing on Plain, so no question asks for them."
},
"requiredProducts": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"maxLength": 100,
"description": "Product slug."
},
"description": "Products that must be selected together with this one, directly or indirectly. Add them to `products` when quoting."
}
},
"description": "An insurance product that can be offered to a Danish company.",
"additionalProperties": false
},
"description": "Products that can be offered."
},
"productDependencies": {
"type": "array",
"items": {
"type": "object",
"required": [
"product",
"requiredProduct"
],
"properties": {
"product": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"maxLength": 100,
"description": "Product slug."
},
"requiredProduct": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"maxLength": 100,
"description": "Slug of a product that must be selected together with `product`."
}
},
"description": "A product that can only be bought together with another.",
"additionalProperties": false
},
"description": "Products that require another product."
}
},
"description": "Products and questions to collect answers for before quoting.",
"additionalProperties": false
}{
"readOnlyHint": true,
"openWorldHint": false,
"destructiveHint": false
}quote_onboarding_products — Quote products
Calculates indicative prices for up to twenty products for the company with this CVR, from one flat `answers` object. A plain key answers a question for the company and for every selected product that asks it; `<product>.<name>` answers one product's question. Stored answers and company discounts are not reused; supply required answers explicitly. An optional partnerCode applies that partner's discount. Enum fields use {value, label: {da, en}}. Each product has a status.value: only `quoted` products have a price; `contactPlain` products need an individual offer from Plain and `unavailable` ones cannot be offered (see `issue`). Prices are in DKK (major units) per billingFrequency.value period, with annualPrice for comparison and totals across products. State prices with each quote's `display` text in the customer's language, and always show the `disclaimer`. When pricePerEmployee is true, the price is per employee: say so using the quote's notice, as the customer selects the covered employees on Plain. Unknown answer keys are ignored and reported in warnings; required answers are never inferred. Nothing is bound, created or charged. Works without signing in, as a public new-company quote. Quotes for an existing customer must use the selected, authorized company's CVR. Active products return status.value alreadyInsured with no new-offer price and are excluded from totals and creation; held prerequisites do not need to be selected again. Check list_companies.canCreateOffers before promising to create offers. Quoting itself only needs policies:read. For existing companies, use get_onboarding_payment_link after creating offers for authenticated review; continueUrl is the public new-company signup page and does not apply private policy exclusions.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"cvr",
"products",
"answers"
],
"properties": {
"cvr": {
"type": "string",
"pattern": "^[0-9]{8}$",
"description": "Danish company registration number (CVR), eight digits, e.g. 39488914."
},
"region": {
"type": "string",
"const": "dk",
"default": "dk",
"description": "Market. Only Denmark (dk) is supported. Optional; defaults to dk."
},
"answers": {
"type": "object",
"description": "Every answer in one object, keyed by the catalog question `name`. A plain name answers that question for the company and for every selected product that asks it; `<product>.<name>` (e.g. loesoereforsikring.basement) answers only that product's question and takes precedence. Employee FTE questions are answered as `<name>.fullTime` and `<name>.partTime` head counts: integers from 0 to 9999 inclusive. When required, send both counts explicitly, including zero.",
"maxProperties": 100,
"propertyNames": {
"type": "string",
"maxLength": 300,
"minLength": 1
},
"additionalProperties": {
"anyOf": [
{
"type": "string",
"maxLength": 2000
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string",
"maxLength": 256
},
"maxItems": 100
}
],
"description": "The answer's JSON type follows the catalog question's `type.value`: Text is a string; NumberWhole is an integer and NumberDecimal a number (numeric strings are accepted); Date is a YYYY-MM-DD string; Boolean is true or false; Select is one option key from `options` as a string; MultiSelect is an array of option keys."
}
},
"products": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"maxLength": 100,
"description": "Product slug from the catalog."
},
"maxItems": 20,
"minItems": 1,
"description": "The products to quote: 1 to 20 distinct slugs, including any products they require.",
"uniqueItems": true
},
"startDate": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "Policy start date (YYYY-MM-DD). Defaults to today. Must be between today and one year ahead."
},
"partnerCode": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{2,64}$",
"description": "Optional partner discount code, 2-64 letters, digits, hyphens or underscores. Must be active."
}
},
"description": "The company, products and answers to price. Send the same object again in /start.",
"additionalProperties": false
}{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"quotes",
"totals",
"quoteId",
"startDate",
"expiresAt",
"continueUrl",
"disclaimer"
],
"properties": {
"quotes": {
"type": "array",
"items": {
"type": "object",
"required": [
"product",
"name",
"termsUrl",
"termsDocuments",
"status",
"currency",
"billingFrequency",
"pricePerEmployee",
"coverage",
"display"
],
"properties": {
"name": {
"type": "string",
"description": "Product name to show next to the price."
},
"issue": {
"type": "object",
"required": [
"code",
"message",
"nextAction"
],
"properties": {
"max": {
"anyOf": [
{
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
{
"type": "number"
}
],
"description": "Inclusive maximum: the latest start date (YYYY-MM-DD) for invalid_start_date, or the numeric upper bound for invalid_answer."
},
"min": {
"anyOf": [
{
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
},
{
"type": "number"
}
],
"description": "Inclusive minimum: the earliest start date (YYYY-MM-DD) for invalid_start_date, or the numeric lower bound for invalid_answer."
},
"code": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"invalid_answer",
"missing_answer",
"ambiguous_question",
"invalid_start_date",
"cvr_not_found",
"invalid_products",
"missing_product",
"invalid_request",
"request_too_large",
"unsupported_media_type",
"wrong_identity_mode",
"idempotency_key_mismatch",
"idempotency_conflict",
"price_changed",
"invalid_partner_code",
"invalid_verification",
"sign_in_required",
"onboarding_expired",
"not_authenticated",
"not_authorized",
"consent_required",
"temporarily_unavailable",
"invalid_backend_response",
"rate_limited",
"operation_in_progress",
"price_unavailable",
"manual_review_required",
"pricing_configuration",
"unsupported_input",
"unexpected_error",
"not_found"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"not_found": {
"da": "Ikke fundet",
"en": "Not found"
},
"rate_limited": {
"da": "For mange forespørgsler",
"en": "Too many requests"
},
"cvr_not_found": {
"da": "CVR-nummer ikke fundet",
"en": "CVR number not found"
},
"price_changed": {
"da": "Prisen er ændret",
"en": "Price changed"
},
"invalid_answer": {
"da": "Ugyldigt svar",
"en": "Invalid answer"
},
"missing_answer": {
"da": "Svar mangler",
"en": "Missing answer"
},
"not_authorized": {
"da": "Ingen adgang",
"en": "Not authorized"
},
"invalid_request": {
"da": "Ugyldig forespørgsel",
"en": "Invalid request"
},
"missing_product": {
"da": "Påkrævet produkt mangler",
"en": "Required product missing"
},
"consent_required": {
"da": "Samtykke påkrævet",
"en": "Consent required"
},
"invalid_products": {
"da": "Ugyldige produkter",
"en": "Invalid products"
},
"sign_in_required": {
"da": "Login påkrævet",
"en": "Sign-in required"
},
"unexpected_error": {
"da": "Uventet fejl",
"en": "Unexpected error"
},
"not_authenticated": {
"da": "Ikke logget ind",
"en": "Not signed in"
},
"price_unavailable": {
"da": "Prisen kan ikke beregnes",
"en": "Price unavailable"
},
"request_too_large": {
"da": "Forespørgslen er for stor",
"en": "Request too large"
},
"unsupported_input": {
"da": "Oplysningerne understøttes ikke",
"en": "Unsupported input"
},
"ambiguous_question": {
"da": "Spørgsmålet er ikke entydigt",
"en": "Ambiguous question"
},
"invalid_start_date": {
"da": "Ugyldig startdato",
"en": "Invalid start date"
},
"onboarding_expired": {
"da": "Tilmeldingen er udløbet",
"en": "Signup expired"
},
"wrong_identity_mode": {
"da": "Forkert godkendelsesmetode",
"en": "Wrong authentication method"
},
"idempotency_conflict": {
"da": "Idempotensnøglen er allerede brugt til andre oplysninger",
"en": "Idempotency key already used for different input"
},
"invalid_partner_code": {
"da": "Ugyldig partnerkode",
"en": "Invalid partner code"
},
"invalid_verification": {
"da": "Ugyldig eller udløbet bekræftelseskode",
"en": "Invalid or expired verification code"
},
"operation_in_progress": {
"da": "Handlingen er i gang",
"en": "Operation in progress"
},
"pricing_configuration": {
"da": "Prisopsætningen skal gennemgås",
"en": "Pricing configuration needs review"
},
"manual_review_required": {
"da": "Individuelt tilbud påkrævet",
"en": "Individual offer required"
},
"unsupported_media_type": {
"da": "Indholdstypen understøttes ikke",
"en": "Unsupported media type"
},
"temporarily_unavailable": {
"da": "Midlertidigt utilgængelig",
"en": "Temporarily unavailable"
},
"idempotency_key_mismatch": {
"da": "Idempotensnøglerne er forskellige",
"en": "Idempotency keys do not match"
},
"invalid_backend_response": {
"da": "Ugyldigt svar fra serveren",
"en": "Invalid backend response"
}
}
}
},
"description": "Error code and its translated labels.",
"additionalProperties": false
},
"field": {
"type": "string",
"description": "Request field to correct, using dot notation for nested fields."
},
"reason": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"industry_not_covered",
"unknown"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"unknown": {
"da": "Ukendt årsag",
"en": "Unknown reason"
},
"industry_not_covered": {
"da": "Branchen er ikke dækket",
"en": "Industry not covered"
}
}
}
},
"description": "For price_unavailable: industry_not_covered when the product has no tariff for the company's industry, otherwise unknown.",
"additionalProperties": false
},
"message": {
"type": "string",
"description": "Human-readable explanation in English."
},
"product": {
"type": "string",
"description": "Slug of the product the error concerns, when it concerns one."
},
"question": {
"type": "string",
"description": "Answer key of the question the error concerns, as used in `answers`."
},
"didYouMean": {
"type": "string",
"description": "Suggested catalog product slug or answer key. Retry only after confirming the intended value."
},
"nextAction": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"fixAnswer",
"askUser",
"retryLater",
"contactPlain",
"none"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"none": {
"da": "Ingen handling nødvendig",
"en": "No action needed"
},
"askUser": {
"da": "Bed kunden om oplysninger eller login",
"en": "Ask the customer for input or to sign in"
},
"fixAnswer": {
"da": "Ret oplysningerne og prøv igen",
"en": "Correct the request and try again"
},
"retryLater": {
"da": "Prøv igen senere",
"en": "Try again later"
},
"contactPlain": {
"da": "Kontakt Plain",
"en": "Contact Plain"
}
}
}
},
"description": "What to do next: fixAnswer (correct the request and retry), askUser (ask the person for new input or to sign in), retryLater (retry the same request later), contactPlain (Plain must review this case; refer the person to Plain), none (nothing to do).",
"additionalProperties": false
},
"allowedValues": {
"type": "array",
"items": {
"type": "string"
},
"description": "For invalid_answer on a select question: the option keys that are accepted."
},
"questionLabel": {
"type": "object",
"required": [
"da"
],
"properties": {
"da": {
"type": "string",
"description": "Danish question label from the catalog."
}
},
"description": "Danish question label, when the question can be identified in the catalog.",
"additionalProperties": false
}
},
"description": "Why the product is not quoted.",
"additionalProperties": false
},
"price": {
"type": "object",
"required": [
"totalPrice",
"premium",
"fees"
],
"properties": {
"fees": {
"type": "number",
"description": "Statutory fees and taxes per billing period, in DKK."
},
"premium": {
"type": "number",
"description": "Insurance premium per billing period, in DKK."
},
"totalPrice": {
"type": "number",
"description": "What the customer pays per billing period, in DKK (major units, kroner): premium plus government fees."
}
},
"description": "The price per billing period; present when quoted.",
"additionalProperties": false
},
"notice": {
"type": "string",
"description": "A message to show the customer with this price, e.g. that it is per employee."
},
"status": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"quoted",
"contactPlain",
"unavailable",
"alreadyInsured"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"quoted": {
"da": "Pris beregnet",
"en": "Quoted"
},
"unavailable": {
"da": "Kan ikke tilbydes",
"en": "Unavailable"
},
"contactPlain": {
"da": "Kontakt Plain",
"en": "Contact Plain"
},
"alreadyInsured": {
"da": "Allerede forsikret",
"en": "Already insured"
}
}
}
},
"description": "quoted: priced and can be sent to /start. contactPlain: Plain makes an individual offer; the customer contacts Plain. unavailable: cannot be offered for these answers; see `issue`. alreadyInsured: active for the authorized company; excluded from new offers and totals. Only quoted products have a price.",
"additionalProperties": false
},
"display": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"description": "Danish."
},
"en": {
"type": "string",
"description": "English."
}
},
"description": "How to state this quote to the customer: total, premium and fees split, and period.",
"additionalProperties": false
},
"product": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"maxLength": 100,
"description": "Product slug."
},
"coverage": {
"type": "object",
"required": [
"sumInsured",
"deductible",
"summary"
],
"properties": {
"summary": {
"type": [
"string",
"null"
],
"description": "What the insurance covers, in brief."
},
"deductible": {
"type": [
"string",
"null"
],
"description": "The deductible (selvrisiko), as text."
},
"sumInsured": {
"type": [
"string",
"null"
],
"description": "The sum insured, as text."
}
},
"description": "What the price buys. Fields are null when the product does not state them.",
"additionalProperties": false
},
"currency": {
"type": "string",
"description": "ISO 4217 currency: DKK."
},
"termsUrl": {
"type": [
"string",
"null"
],
"description": "Link to the product's insurance terms as PDF. Same as `termsDocuments.termsPdf`."
},
"annualPrice": {
"type": "object",
"required": [
"totalPrice",
"premium",
"fees"
],
"properties": {
"fees": {
"type": "number",
"description": "Statutory fees and taxes per billing period, in DKK."
},
"premium": {
"type": "number",
"description": "Insurance premium per billing period, in DKK."
},
"totalPrice": {
"type": "number",
"description": "What the customer pays per billing period, in DKK (major units, kroner): premium plus government fees."
}
},
"description": "The price per year, to compare monthly and annual products; present when quoted.",
"additionalProperties": false
},
"termsDocuments": {
"anyOf": [
{
"type": "object",
"required": [
"termsPdf",
"ipidPdf",
"ipidYaml",
"termsMarkdown"
],
"properties": {
"ipidPdf": {
"type": "string",
"description": "Insurance product information document (IPID) as PDF. Give this link to the customer."
},
"ipidYaml": {
"type": "string",
"description": "The IPID as YAML, for agents to read the key facts: what is and is not covered, restrictions and obligations."
},
"termsPdf": {
"type": "string",
"description": "Full insurance terms as PDF. Give this link to the customer."
},
"termsMarkdown": {
"type": "string",
"description": "Full insurance terms as Markdown, for agents to read and answer questions about coverage."
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Links to the product's terms documents, or null when it has none. Read the YAML and Markdown to answer questions; give the customer the PDF links. External terms use the same link for all four."
},
"billingFrequency": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"Monthly",
"Annual"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"Annual": {
"da": "Årlig",
"en": "Annual"
},
"Monthly": {
"da": "Månedlig",
"en": "Monthly"
}
}
}
},
"description": "How often the customer pays: Monthly or Annual. Prices are per period of this frequency.",
"additionalProperties": false
},
"pricePerEmployee": {
"type": "boolean",
"description": "Whether `price` is per covered employee. The customer selects the employees when purchasing on Plain, which sets the total."
}
},
"description": "The indicative price of one product, or why it has none.",
"additionalProperties": false
},
"description": "One quote per selected product, in request order."
},
"totals": {
"anyOf": [
{
"type": "object",
"required": [
"monthly",
"annual",
"excludedProducts",
"display"
],
"properties": {
"annual": {
"type": "object",
"required": [
"totalPrice",
"premium",
"fees"
],
"properties": {
"fees": {
"type": "number",
"description": "Statutory fees and taxes per billing period, in DKK."
},
"premium": {
"type": "number",
"description": "Insurance premium per billing period, in DKK."
},
"totalPrice": {
"type": "number",
"description": "What the customer pays per billing period, in DKK (major units, kroner): premium plus government fees."
}
},
"description": "Sum per year.",
"additionalProperties": false
},
"display": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"description": "Danish."
},
"en": {
"type": "string",
"description": "English."
}
},
"description": "How to state the totals to the customer.",
"additionalProperties": false
},
"monthly": {
"type": "object",
"required": [
"totalPrice",
"premium",
"fees"
],
"properties": {
"fees": {
"type": "number",
"description": "Statutory fees and taxes per billing period, in DKK."
},
"premium": {
"type": "number",
"description": "Insurance premium per billing period, in DKK."
},
"totalPrice": {
"type": "number",
"description": "What the customer pays per billing period, in DKK (major units, kroner): premium plus government fees."
}
},
"description": "Sum per month; annual products count as a twelfth of their yearly price.",
"additionalProperties": false
},
"excludedProducts": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"maxLength": 100,
"description": "Product slug."
},
"description": "Selected products not in the totals: not quoted, or priced per employee."
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Totals of the quoted products; null when no product is included."
},
"quoteId": {
"type": [
"string",
"null"
],
"description": "Identifies these prices; pass it as `quoteId` to /start with the exact original quote request. Only quoted products become offers. Null when no product is quoted."
},
"warnings": {
"type": "array",
"items": {
"type": "object",
"required": [
"code",
"question"
],
"properties": {
"code": {
"type": "string",
"const": "unknown_question",
"description": "An unrecognized answer key was ignored; no answer was inferred from it."
},
"question": {
"type": "string",
"description": "The ignored answer key. Check the catalog for the correct name."
},
"didYouMean": {
"type": "string",
"description": "Suggested answer key. Confirm it before resending; answers are never auto-corrected."
},
"questionLabel": {
"type": "object",
"required": [
"da"
],
"properties": {
"da": {
"type": "string",
"description": "Danish question label from the catalog."
}
},
"description": "Danish label of the suggested question, when available.",
"additionalProperties": false
}
},
"additionalProperties": false
},
"description": "Non-fatal problems with ignored answers. Omitted when there are none."
},
"expiresAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "Until when quoteId can be used for /start, unless prices change first; then request a new quote."
},
"startDate": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "The insurance start date the prices apply to; today when the request has none."
},
"disclaimer": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"description": "Danish."
},
"en": {
"type": "string",
"description": "English."
}
},
"description": "Show with the prices: they are indicative, and nothing binds until the customer signs on Plain.",
"additionalProperties": false
},
"continueUrl": {
"type": "string",
"format": "uri",
"description": "Where the customer reviews this quote on Plain and continues to sign up. Opening it creates nothing."
}
},
"description": "Indicative prices. Nothing is bound or charged.",
"additionalProperties": false
}{
"readOnlyHint": true,
"openWorldHint": false,
"destructiveHint": false
}create_onboarding — Create unsigned insurance offers
Recalculates an approved quote and creates offered, unsigned policies, ready for the customer to review and sign on Plain. Send the exact quote request again with its quoteId before expiresAt; offers are created for the products with status.value quoted only. Active insurance is rechecked before creation. Retry a failed request on the same connection with the same idempotency key and body. No insurance is accepted, activated or charged. When state.value is awaiting_verification, ask the person for the emailed code. Creates offers for the selected, authorized existing company without recreating it, or onboards a new company. For an existing company, select it with set_company_context and use its CVR; administrator access is required. Uses the connected user's identity: omit email and name. Requires signing in with onboarding:write consent; calling it prompts sign-in when needed. Check list_companies first. idempotencyKey is required. If the connected user's email is confirmed, no email code is needed. Do not reuse a retry key across reconnections; obtain a fresh quote after expiry or insurance changes.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"quote",
"quoteId"
],
"properties": {
"name": {
"type": "string",
"maxLength": 200,
"minLength": 1,
"description": "Full name of the person signing up. Must not contain links or markup."
},
"email": {
"type": "string",
"format": "email",
"pattern": "^(?:[A-Za-z0-9_'+\\-]+\\.)*[A-Za-z0-9_'+\\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$",
"maxLength": 254,
"description": "Email address of the person signing up; a verification code is sent here."
},
"quote": {
"type": "object",
"required": [
"cvr",
"products",
"answers"
],
"properties": {
"cvr": {
"type": "string",
"pattern": "^[0-9]{8}$",
"description": "Danish company registration number (CVR), eight digits, e.g. 39488914."
},
"region": {
"type": "string",
"const": "dk",
"default": "dk",
"description": "Market. Only Denmark (dk) is supported. Optional; defaults to dk."
},
"answers": {
"type": "object",
"description": "Every answer in one object, keyed by the catalog question `name`. A plain name answers that question for the company and for every selected product that asks it; `<product>.<name>` (e.g. loesoereforsikring.basement) answers only that product's question and takes precedence. Employee FTE questions are answered as `<name>.fullTime` and `<name>.partTime` head counts: integers from 0 to 9999 inclusive. When required, send both counts explicitly, including zero.",
"maxProperties": 100,
"propertyNames": {
"type": "string",
"maxLength": 300,
"minLength": 1
},
"additionalProperties": {
"anyOf": [
{
"type": "string",
"maxLength": 2000
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string",
"maxLength": 256
},
"maxItems": 100
}
],
"description": "The answer's JSON type follows the catalog question's `type.value`: Text is a string; NumberWhole is an integer and NumberDecimal a number (numeric strings are accepted); Date is a YYYY-MM-DD string; Boolean is true or false; Select is one option key from `options` as a string; MultiSelect is an array of option keys."
}
},
"products": {
"type": "array",
"items": {
"type": "string",
"pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$",
"maxLength": 100,
"description": "Product slug from the catalog."
},
"maxItems": 20,
"minItems": 1,
"description": "The products to quote: 1 to 20 distinct slugs, including any products they require.",
"uniqueItems": true
},
"startDate": {
"type": "string",
"format": "date",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
"description": "Policy start date (YYYY-MM-DD). Defaults to today. Must be between today and one year ahead."
},
"partnerCode": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{2,64}$",
"description": "Optional partner discount code, 2-64 letters, digits, hyphens or underscores. Must be active."
}
},
"description": "The company, products and answers to price. Send the same object again in /start.",
"additionalProperties": false
},
"quoteId": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "The `quoteId` of the quote the person approved."
},
"idempotencyKey": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{32,128}$",
"description": "Random key of 32-128 letters, digits, hyphens or underscores. Retry a failed request with the same key and body."
}
},
"description": "Creates unsigned offers from an approved quote; public signup also creates the company.",
"additionalProperties": false
}{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"onboardingId",
"capability",
"state",
"policyIds"
],
"properties": {
"state": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"awaiting_verification",
"email_confirmed",
"verified"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"verified": {
"da": "Tilbud klar",
"en": "Offers ready"
},
"email_confirmed": {
"da": "E-mail bekræftet",
"en": "Email confirmed"
},
"awaiting_verification": {
"da": "Afventer e-mailbekræftelse",
"en": "Awaiting email verification"
}
}
}
},
"description": "awaiting_verification: ask the person for the emailed code; email_confirmed: call /verify-email again to finish; verified: offers are ready.",
"additionalProperties": false
},
"policyIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "IDs of the offered policies, once created."
},
"capability": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "Secret proof of this signup. Keep it private and send it with onboardingId."
},
"onboardingId": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "Identifies this signup."
},
"continuationToken": {
"anyOf": [
{
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
{
"type": "null"
}
],
"description": "Secret token for /payment-handoff, valid for 15 minutes after verification."
}
},
"description": "The state of a signup.",
"additionalProperties": false
}{
"readOnlyHint": false,
"openWorldHint": false,
"destructiveHint": false
}verify_onboarding_email — Confirm the signup email
Confirms the signup email with the eight-digit code the person received. Codes expire after 15 minutes and allow five attempts. Keep the returned capability and continuationToken private. Does not activate insurance.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"onboardingId",
"capability",
"code"
],
"properties": {
"code": {
"type": "string",
"pattern": "^[0-9]{8}$",
"description": "The eight-digit code from the verification email. Valid for 15 minutes, five attempts."
},
"capability": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "From the /start result."
},
"onboardingId": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "From the /start result."
}
},
"description": "Confirms the signup email with the emailed code.",
"additionalProperties": false
}{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"onboardingId",
"capability",
"state",
"policyIds"
],
"properties": {
"state": {
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"awaiting_verification",
"email_confirmed",
"verified"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"verified": {
"da": "Tilbud klar",
"en": "Offers ready"
},
"email_confirmed": {
"da": "E-mail bekræftet",
"en": "Email confirmed"
},
"awaiting_verification": {
"da": "Afventer e-mailbekræftelse",
"en": "Awaiting email verification"
}
}
}
},
"description": "awaiting_verification: ask the person for the emailed code; email_confirmed: call /verify-email again to finish; verified: offers are ready.",
"additionalProperties": false
},
"policyIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "IDs of the offered policies, once created."
},
"capability": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "Secret proof of this signup. Keep it private and send it with onboardingId."
},
"onboardingId": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "Identifies this signup."
},
"continuationToken": {
"anyOf": [
{
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
{
"type": "null"
}
],
"description": "Secret token for /payment-handoff, valid for 15 minutes after verification."
}
},
"description": "The state of a signup.",
"additionalProperties": false
}{
"readOnlyHint": false,
"openWorldHint": false,
"destructiveHint": false
}get_onboarding_payment_link — Get the link to sign on Plain
Returns a one-time link, valid for five minutes, where the person reviews the offers and sets up payment on Plain. The person must open and confirm it. Setting up payment does not accept the offers or charge money. Use the same authorized connection that created the offers and keep the target company selected; continuationToken may then be omitted.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"onboardingId",
"capability"
],
"properties": {
"capability": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "From the /start result."
},
"onboardingId": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "From the /start result."
},
"continuationToken": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "The continuationToken from the /verify-email result."
}
},
"description": "Requests a link for the person to review the offers and set up payment on Plain.",
"additionalProperties": false
}{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"url",
"expiresAt"
],
"properties": {
"url": {
"type": "string",
"format": "uri",
"description": "One-time link to open in the person's browser. Valid for five minutes."
},
"expiresAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$",
"description": "When the link expires (ISO 8601 date-time)."
}
},
"description": "A browser link to Plain where the person reviews and signs the offers.",
"additionalProperties": false
}{
"readOnlyHint": false,
"openWorldHint": false,
"destructiveHint": false
}list_companies — List permitted companies
Requires signing in to Plain; calling it prompts sign-in when needed. Lists companies explicitly approved for this Plain connection that you still have access to, and marks the active company. Reports granted scopes and whether the connection can create unsigned offers. Check this before quoting for an existing company or offering to create offers. Reconnect requesting onboarding:write to approve offer creation, or reconnect to approve additional companies. Company permissions are checked separately when creating offers.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"properties": {},
"additionalProperties": false
}{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"companies",
"scopes",
"canCreateOffers"
],
"properties": {
"scopes": {
"type": "array",
"items": {
"type": "string"
}
},
"companies": {
"type": "array",
"items": {
"type": "object",
"required": [
"companyId",
"companyName",
"isCurrent"
],
"properties": {
"companyId": {
"type": "string"
},
"isCurrent": {
"type": "boolean"
},
"companyName": {
"type": "string"
}
},
"additionalProperties": false
}
},
"canCreateOffers": {
"type": "boolean"
}
},
"additionalProperties": false
}{
"readOnlyHint": true,
"openWorldHint": false,
"destructiveHint": false
}set_company_context — Set active company
Requires signing in to Plain. Changes the active Plain company for subsequent tool calls on this connection. Use an exact companyId from list_companies. All chats sharing this authorization share the selection. Already-running requests may finish for the previous company.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"companyId"
],
"properties": {
"companyId": {
"type": "string",
"maxLength": 256,
"minLength": 1
}
},
"additionalProperties": false
}{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"companyId",
"companyName",
"isCurrent"
],
"properties": {
"companyId": {
"type": "string"
},
"isCurrent": {
"type": "boolean"
},
"companyName": {
"type": "string"
}
},
"additionalProperties": false
}{
"readOnlyHint": false,
"openWorldHint": false,
"idempotentHint": true,
"destructiveHint": false
}list_active_policies — List active policies
Requires signing in to Plain; calling it prompts sign-in when needed. Lists the active insurance policies for the currently selected Plain company on this connection, including product, carrier, dates, price and billing details. Amounts are in major currency units (e.g. DKK). totalPrice is the total price the customer pays; it is legally required to be split into the insurance premium and fees (statutory fees and taxes). Whenever you mention a price, state the total and its split into premium and fees.
{
"type": "object",
"properties": {}
}{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"policies"
],
"properties": {
"policies": {
"type": "array",
"items": {
"type": "object",
"required": [
"id",
"policyNumber",
"productName",
"product",
"carrierName",
"description",
"coverage",
"startDate",
"endDate",
"totalPrice",
"premium",
"fees",
"currency",
"billingFrequency",
"termsUrl"
],
"properties": {
"id": {
"type": [
"string",
"null"
]
},
"fees": {
"type": [
"number",
"null"
],
"description": "Statutory fees and taxes part of totalPrice, in major currency units. Not part of the premium."
},
"endDate": {
"type": [
"string",
"null"
]
},
"premium": {
"type": [
"number",
"null"
],
"description": "Insurance premium part of totalPrice, in major currency units. Excludes fees."
},
"product": {
"type": [
"string",
"null"
],
"description": "Public product slug for matching the onboarding catalog, when available."
},
"coverage": {
"type": [
"string",
"null"
]
},
"currency": {
"type": [
"string",
"null"
]
},
"termsUrl": {
"type": [
"string",
"null"
]
},
"startDate": {
"type": [
"string",
"null"
]
},
"totalPrice": {
"type": [
"number",
"null"
],
"description": "Total price per billing period in major currency units (e.g. DKK, not øre). This is the full amount the customer pays and equals premium + fees. Never present it as the premium alone."
},
"carrierName": {
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"productName": {
"type": [
"string",
"null"
]
},
"policyNumber": {
"type": [
"string",
"null"
]
},
"billingFrequency": {
"anyOf": [
{
"type": "object",
"required": [
"value",
"label"
],
"properties": {
"label": {
"type": "object",
"required": [
"da",
"en"
],
"properties": {
"da": {
"type": "string",
"minLength": 1,
"description": "Danish label."
},
"en": {
"type": "string",
"minLength": 1,
"description": "English label."
}
},
"description": "Human-readable labels by language.",
"additionalProperties": false
},
"value": {
"enum": [
"Monthly",
"Annual"
],
"type": "string",
"description": "Stable machine-readable value.",
"x-enum-labels": {
"Annual": {
"da": "Årlig",
"en": "Annual"
},
"Monthly": {
"da": "Månedlig",
"en": "Monthly"
}
}
}
},
"description": "How often the customer pays: Monthly or Annual. Prices are per period of this frequency.",
"additionalProperties": false
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
}{
"readOnlyHint": true,
"openWorldHint": false,
"destructiveHint": false
}Prompts
Not advertised
Resources
Not advertised
90-day uptime
A lightweight connection check about every six hours, sampled on hosts with many listings. It shows the server answered, not that its tools work.
- 2026-11-07: 1 of 1 checks answered
30-day availability
Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.
- Successful checks
- 1 of 1 (100%)
- Average latency
- 2116 ms
- 95th percentile latency
- 2116 ms
Maintenance history
Public check and source-refresh events. Editorial and ownership records remain private.
- · probe · passed · 2116 ms · metadata changed · 8 tool(s)
Connect from your client
Each snippet registers the same endpoint; pick the client you use.
Claude Code
claude mcp add --transport http plain-insurance-mcp https://app.plain.insurance/api/mcpCodex
codex mcp add plain-insurance-mcp --url https://app.plain.insurance/api/mcpCursor
{
"mcpServers": {
"plain-insurance-mcp": {
"url": "https://app.plain.insurance/api/mcp"
}
}
}Cline
{
"mcpServers": {
"plain-insurance-mcp": {
"type": "streamableHttp",
"url": "https://app.plain.insurance/api/mcp",
"disabled": false
}
}
}VS Code
{
"servers": {
"plain-insurance-mcp": {
"type": "http",
"url": "https://app.plain.insurance/api/mcp"
}
}
}Gemini CLI
gemini mcp add --transport http plain-insurance-mcp https://app.plain.insurance/api/mcpClaude Desktop
https://app.plain.insurance/api/mcpWindsurf
{
"mcpServers": {
"plain-insurance-mcp": {
"serverUrl": "https://app.plain.insurance/api/mcp"
}
}
}Let your agent find its tools
Find servers like Plain Insurance MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.
Other payments servers
Do you run Plain Insurance MCP?
Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.