Developer · API

The Swallow REST API

Price quotes in real time, manage projects and versions, save tests and read your quote history. It's JSON in and JSON out, and every user signs requests with their own keys

Authentication

Your keys, on every request

Send client_id_key and client_secret_key as headers. Find them in the dashboard under Settings → API Keys: user keys act as you, and company keys suit server-to-server integrations. Recycle either pair whenever you like

curl https://api.llow.io/a/users/me \
  -H "client_id_key: $SWALLOW_CLIENT_ID" \
  -H "client_secret_key: $SWALLOW_CLIENT_SECRET"
Settings API Keys page with user keys and company keys, each with a client ID key, client secret key and a recycle keys button
Quickstart

Price a model

The pet insurance model priced for a 3-year-old neutered Persian in Greater London. The body is the flat set of fields the model defines, and the optional client_ref is saved with the quote

Request
curl -X POST "https://api.llow.io/sw/quotes/$PROJECT_REFERENCE?client_ref=POL-10234" \
  -H "client_id_key: $SWALLOW_CLIENT_ID" \
  -H "client_secret_key: $SWALLOW_CLIENT_SECRET" \
  -H "content-type: application/json" \
  -d '{"species":"cat","breed":"persian","pet_age":3,"region":"greater_london","vet_fee_limit":4000,"excess":100,"neutered":true}'
Response, trimmed
{
  "quote_reference": "<uuid>",
  "project_reference": "<uuid>",
  "version_reference": "<uuid>",
  "version": 1,
  "result": 255.34,
  "valid": true,
  "refers": [],
  "exclusions": [],
  "excesses": [],
  "endorsements": [],
  "input": {
    "species": "cat",
    "breed": "persian",
    "pet_age": 3,
    "region": "greater_london",
    "vet_fee_limit": 4000,
    "excess": 100,
    "neutered": true
  },
  "output": {
    "risk_premium": 227.98,
    "ipt": 27.36,
    "monthly_premium": 21.28,
    "base_premium": 142,
    "refer": false,
    "result": 255.34,
    "valid": true
  },
  "client_ref": "POL-10234",
  "created_at": "<timestamp>"
}
Added with ?debug=true, trimmed to two steps
{
  "debug": {
    "meta": {
      "name": "UK Pet Insurance: Cats and Dogs"
    },
    "timer": [
      {
        "time": 0,
        "elapsed": 0.096,
        "key": "input"
      },
      {
        "time": 0.268,
        "elapsed": 0.1,
        "key": "breed_factors"
      },
      {
        "time": 1.001,
        "elapsed": 0.132,
        "key": "output"
      }
    ],
    "steps": {
      "breed_factors": {
        "errors": [],
        "items": [],
        "output": {
          "breed_factor": 1.3,
          "breed_matches": 1
        }
      },
      "risk_premium": {
        "errors": [],
        "items": [
          {
            "formula": "round({{base_premium}} * {{pet_age_factor}} * {{breed_factor}} * {{region_factor}} * {{excess_factor}} * {{neuter_factor}}, 2)",
            "result": 227.98,
            "base_premium": 142,
            "pet_age_factor": 1,
            "breed_factor": 1.3,
            "region_factor": 1.3,
            "excess_factor": 1,
            "neuter_factor": 0.95
          }
        ],
        "output": {
          "risk_premium": 227.98
        }
      }
    },
    "exclusions": [],
    "refers": [],
    "excesses": [],
    "endorsements": [],
    "indicators": {},
    "errors": []
  }
}
What comes back
result
The annual premium with IPT: 255.34
valid
true when no exclusion fired. A declined quote still has a price, but mustn't be bound
quote_reference
The saved quote. Fetch it again with GET /sw/quotes/:quote_reference
output
Every field the model returns, like the monthly figure and refer, which is true when an underwriter must sign off first
version
The version that priced it, with its version_reference, so each quote ties back to an exact model. Leave the version out of the request and the latest published one is used
refers · exclusions
The refer and exclusion rules that fired. Empty lists mean a clean quote
debug
Add ?debug=true to get every input, lookup, formula and rule the engine worked through, with timings and warnings. Quoting shows how to read it
dry_run
Add ?dry_run=true to price without saving the quote or firing any exports
How 255.34 adds up
Base premiumcat, 4,000 limit142.00
× Age factorage 3, band 2 to 41.00
× Breed factorPersian1.30
× Region factorGreater London1.30
× Excess factor100 excess1.00
× Neutered factorneutered0.95
= Risk premiumto the penny227.98
+ IPT at 12%27.36
= Annual premiumresult255.34
Monthly÷ 1221.28
Try page API tab showing a ready-to-run curl request for the model, with tabs for Swallow CLI, Node, Python and .NET
Reference

39 endpoints

All paths sit under https://api.llow.io. Pricing lives under /sw and your users and company under /a

QuotesPrice risks, then read, amend and report on them
POST/sw/quotes/:project_referenceRun a quote

Prices the request body against a project and saves the quote. The body is the flat set of inputs the model defines. Without version_reference it uses the latest published version. Add debug=true for the full step trace, dry_run=true to price without saving or firing exports, client_ref to tag the quote with your own reference and date to price against the version that was live on that date.

GET/sw/quotesList quotes

Your saved quotes, newest first. Filter by project_reference, version_reference or since, search the indexed fields with search, and pass lite=true to leave out the input and output.

GET/sw/quotes/:quote_referenceGet a quote

One saved quote with its input, output, version and any changes made to it. Add debug=true for the step trace it was priced with.

PUT/sw/quotes/:quote_referenceAmend a quote

Overrides a saved quote's result, validity or output and adds the change, with your comment, to the quote's history.

POST/sw/quote-salesRecord a sale

Marks a quote as sold, or unsold, so sales show up next to quotes in your analytics.

GET/sw/quotes/analyticsQuote analytics

Quote and sales counts over time for a period, across your account or narrowed to one project or version.

POST/sw/quotes-large/:project_referenceRun a quote on a very large model

The same as running a quote, except that with debug=true the trace isn't sent inline. You get its size and a link to download it from GET /sw/quotes/large/:quote_reference instead. Use it when a model's trace could pass 10 MB.

POST/sw/public/quotes/:project_referenceRun a quote without keys

Prices a quote against a project you have made public, with no credentials. This is what embedded quote forms use.

POST/sw/quotes/eraseErase quote data

Removes personal data from up to 1,000 saved quotes for a GDPR request. Run it with preflight=true first to see what would change. Admins only.

ProjectsYour pricing products and their settings
GET/sw/projectsList projects

Your projects and their versions. Filter by status or archived, and page with limit and offset. Users who aren't admins only see the projects they've been added to.

GET/sw/projects/:project_referenceGet a project

A project's latest approved version, or its draft if nothing has been approved yet. Pass status or version_reference to choose another.

POST/sw/projectsCreate a project

Creates a project from a model. Its first version is published straight away, so you can quote against it at once.

PUT/sw/projects/:project_referenceUpdate a project

Changes project settings: is_public and public_config for quoting without keys, plus group, type and disabled to archive or restore it.

DELETE/sw/projects/:project_referenceArchive a project

Archives a project and all its versions. Admins only.

GET/sw/public/projects/:project_referenceGet a public project

The published inputs, options and theme of a public project, for building your own quote form. No credentials needed.

VersionsEach model, moving from draft to approved to published
GET/sw/projects/versionsList versions

The versions of your projects. Pass a date to find the version that was live at that moment.

GET/sw/projects/versions/:version_referenceGet a version

One version's full model.

POST/sw/projects/versionsStart a new version

Copies the latest published or approved version into a new draft with the next version number. A project has one draft at a time.

PUT/sw/projects/versions/:version_referenceUpdate a version

Saves changes to a draft's model, or moves a version on. Set status to approved, then to published to make it live. Approving and publishing are timestamped and fire your webhooks. A version can also go back to draft.

DELETE/sw/projects/versions/:version_referenceDelete a draft

Deletes a draft. Approved and published versions can't be deleted. Admins only.

GET/sw/projects/versions/large/:version_referenceDownload a large model

A signed link to download a version's model file directly, for models too big for a normal response.

PUT/sw/projects/versions/large/:version_referenceUpload a large model

A signed link to upload a model file straight into a draft. PUT the raw JSON to it.

Tests & processThe test suite and team process saved on each version
GET/sw/tests/:version_referenceGet a version's tests

The test suite saved on a version.

POST/sw/tests/:version_referenceSave tests

Replaces a draft's test suite. Each test pins an input to the result you expect. It's checked against the tests schema and your plan's test limit.

GET/sw/process/:version_referenceGet a version's process

The team, roles and summary saved on a version.

POST/sw/process/:version_referenceSave the process

Sets a draft's summary and team: who can read, write and approve it, and who is told when it starts or is approved.

SchemasWhat a project expects in, and what it sends back
GET/sw/schema/input/:project_referenceInput schema

A JSON Schema of the fields a project needs to price a quote. Handy for validating requests or generating forms.

GET/sw/schema/output/:project_referenceOutput schema

A JSON Schema of what a project sends back.

ActivityComments, approvals and other events on a version
GET/sw/actionsList activity

Comments, approvals, publishes, issues and tasks on your versions, newest first. Filter by project, version, user or date, up to limit (100 by default).

POST/sw/actionsAdd activity

Adds a comment, issue or other event to a version, and can mention teammates.

PUT/sw/actions/:action_referenceEdit activity

Edits or deletes an event you created.

Users & companyYour team and your company account
GET/a/users/meWho am I?

The user behind the keys or token you sent. A quick way to check your credentials work.

GET/a/usersList users

Everyone in your company account.

POST/a/usersAdd a user

Adds a teammate to your company account.

PUT/a/users/:user_referenceUpdate a user

Changes a user's admin rights or turns them off. Send refresh_keys: true to recycle their API keys.

DELETE/a/users/:user_referenceRemove a user

Removes a user from your company.

GET/a/companys/:company_referenceGet your company

Your company's details.

PUT/a/companys/:company_referenceUpdate your company

Changes your company's details, or recycles the company API keys.

ReferenceThe machine-readable spec
GET/sw/openapiOpenAPI spec

An OpenAPI document for the pricing API, for generating clients or importing into Postman. No credentials needed.