Products

Your organisation's products, as they're sold right now: the terms customers see (cooling-off period, what's included and excluded) and the limits on the cover you can quote for (amounts, ages and terms).

Your organisation's products, as they're sold right now: the terms customers see (cooling-off period, what's included and excluded) and the limits on the cover you can quote for (amounts, ages and terms).

Products come from the current release of each product, so changes you're still working on in the dashboard don't show here until they're published.

List your products

GET https://subcontext.com/api/v1/products Try it

Token scopes: read or write

Every product your organisation makes, in name order, whatever its state. Check lifecycle_state for the ones on sale (production).

Responses

200 Your products.

FieldTypeDescription
data required array of Product

The products, in name order.

data[].id required string (uuid)

The product's id.

data[].display_id required string

The id as Subcontext shows it, prod_ and the id.

data[].slug required string

The product's slug, used in addresses such as /api/v1/products/{slug}.

data[].name required string

The product's name, as customers see it.

data[].product_type required string

What kind of product it is.

One of: "term", "decreasing_term", "whole_of_life", "critical_illness", "income_protection", "bundled", "child_cover", "healthcare"
data[].currency_code required string

The currency it's priced in (ISO 4217), such as GBP.

data[].lifecycle_state required string

Where the product is in its life. Only production products are sold to the public.

One of: "draft", "sandbox", "production", "archived"
data[].cooldown_days required integer

The cooling-off period, in days, during which a customer can cancel for a full refund.

data[].inclusions required array of string

What the product includes, as short sentences for customers.

data[].exclusions required array of string

What the product doesn't cover, as short sentences for customers.

data[].cover_bounds required CoverBounds

The limits for a quote across all the product's covers: the lowest and highest amount, age at the start and term. Each is null when the product has no covers (or, for terms, no cover with a fixed term).

data[].cover_bounds.sum_assured_min_pence required integer or null

The smallest amount of cover, in whole pence (the smallest unit of the product's currency).

data[].cover_bounds.sum_assured_max_pence required integer or null

The largest amount of cover, in whole pence.

data[].cover_bounds.age_min required integer or null

The youngest age, in years, at which cover can start.

data[].cover_bounds.age_max required integer or null

The oldest age at which cover can start.

data[].cover_bounds.term_min required integer or null

The shortest term, in years.

data[].cover_bounds.term_max required integer or null

The longest term, in years.

data[].covers required array of Cover

The covers that make up the product, such as life cover with critical illness cover added.

data[].covers[].id required string (uuid)

The cover's id.

data[].covers[].display_id required string

The id as Subcontext shows it, cov_ and the id.

data[].covers[].cover_type required string

What the cover pays out for.

One of: "life", "critical_illness", "income_protection", "accidental_death", "child_benefit", "healthcare"
data[].covers[].cover_index required integer

The cover's position in the product, starting at 0.

data[].covers[].sum_assured_min_pence required integer

The smallest amount of cover, in whole pence (the smallest unit of the product's currency). For a monthly benefit, the yearly amount.

data[].covers[].sum_assured_max_pence required integer

The largest amount of cover, in whole pence.

data[].covers[].age_at_entry_min required integer

The youngest age, in years, at which this cover can start.

data[].covers[].age_at_entry_max required integer

The oldest age at which this cover can start.

data[].covers[].term_years_min required integer or null

The shortest term in years, or null for cover with no fixed term.

data[].covers[].term_years_max required integer or null

The longest term in years, or null for cover with no fixed term.

data[].covers[].max_age_at_expiry required integer or null

The oldest the person can be when the cover ends, if there's a limit.

data[].covers[].premium_basis required string

Whether the price is fixed for the whole term (guaranteed) or reviewed from time to time (reviewable).

One of: "guaranteed", "reviewable"
data[].covers[].review_period_years required integer or null

For reviewable premiums, how often in years the price is reviewed.

data[].covers[].minimum_premium_pence required integer

The lowest monthly premium, in pence (or the smallest unit of the product's currency).

data[].covers[].ci_payout_basis required string

For critical illness cover, whether it pays out on top of life cover (additional) or as an early part of it (accelerated).

One of: "additional", "accelerated"
data[].covers[].survival_period_days required integer

How many days the person must survive after a diagnosis for a critical illness claim.

data[].covers[].indexation_method required string

How the amount of cover changes over the term.

One of: "none", "rpi", "fixed_percent", "decreasing"
data[].covers[].benefit_basis required string

Whether the cover pays a lump sum or a monthly benefit.

One of: "lump_sum", "monthly_benefit"
data[].covers[].title required string or null

The cover's name where its type alone doesn't say which it is, such as one level of a group plan (Diagnosis); otherwise null.

data[].covers[].pricing_basis required string

How the cover is priced: by underwriting and rate tables (rated), from a fixed list of cover levels, each with its own price (fixed_tiers), or at a monthly price for each person on it (per_member, an employer's group plan). A per-member cover has no amount of cover or term: its quote is sized by headcounts.

One of: "rated", "fixed_tiers", "per_member"
data[].covers[].member_premium_pence required integer or null

For a per_member cover, the monthly price for each person on it, in whole pence; otherwise null.

data[].covers[].members_factor required string or null

For a per_member cover, the key of the answer that holds how many people it covers, sent in risk_factors; otherwise null.

data[].covers[].opt_in_factor required string or null

For a per_member add-on, the key of the yes or no answer that adds it to the plan (it then covers the number of people members_factor names); null for a cover that's always included, and for any other cover.

Example
{
  "data": [
    {
      "id": "0199a3c2-5d1e-7b4a-9c3f-2e8d4b6a1f07",
      "display_id": "prod_0199a3c2-5d1e-7b4a-9c3f-2e8d4b6a1f07",
      "slug": "level-term-life",
      "name": "Level Term Life",
      "product_type": "term",
      "currency_code": "GBP",
      "lifecycle_state": "production",
      "cooldown_days": 30,
      "inclusions": [
        "Terminal illness benefit, paid early if you're diagnosed with 12 months or less to live"
      ],
      "exclusions": [
        "Death caused by a deliberately self-inflicted injury in the first year"
      ],
      "cover_bounds": {
        "sum_assured_min_pence": 1000000,
        "sum_assured_max_pence": 50000000,
        "age_min": 18,
        "age_max": 65,
        "term_min": 5,
        "term_max": 40
      },
      "covers": [
        {
          "id": "0199a3c2-5d1e-7b4a-9c3f-2e8d4b6a1f08",
          "display_id": "cov_0199a3c2-5d1e-7b4a-9c3f-2e8d4b6a1f08",
          "cover_type": "life",
          "cover_index": 0,
          "sum_assured_min_pence": 1000000,
          "sum_assured_max_pence": 50000000,
          "age_at_entry_min": 18,
          "age_at_entry_max": 65,
          "term_years_min": 5,
          "term_years_max": 40,
          "max_age_at_expiry": 80,
          "premium_basis": "guaranteed",
          "review_period_years": null,
          "minimum_premium_pence": 500,
          "ci_payout_basis": "additional",
          "survival_period_days": 14,
          "indexation_method": "none",
          "benefit_basis": "lump_sum",
          "title": null,
          "pricing_basis": "rated",
          "member_premium_pence": null,
          "members_factor": null,
          "opt_in_factor": null
        }
      ]
    }
  ]
}

401 No token was sent, or it isn't valid because it has expired, was revoked (for example because the application's secret was rotated), or was cut short. Get a new token and try once more.

FieldTypeDescription
error required object
error.code required string

A short code for the kind of error, such as invalid_token, forbidden, not_found or validation_failed. Each code means one thing wherever it appears.

error.message required string

What went wrong and what to do about it, in plain English.

error.fields object

When the error is about particular inputs, which ones and why, by name: a nested one with a dot (customer.email), one in a list with its place (components[0].term_years). Left out when the error isn't about particular inputs.

Example
{
  "error": {
    "code": "invalid_token",
    "message": "The access token has expired. Ask for a new one."
  }
}

403 The token can't be used here. It's missing a scope, it was used from the wrong place (a server-only application's token in a browser, or a browser application's token from a server, another website or a request only server-only applications may make), or it wasn't asked for with `resource=https://subcontext.com/api/v1`.

FieldTypeDescription
error required object
error.code required string

A short code for the kind of error, such as invalid_token, forbidden, not_found or validation_failed. Each code means one thing wherever it appears.

error.message required string

What went wrong and what to do about it, in plain English.

error.fields object

When the error is about particular inputs, which ones and why, by name: a nested one with a dot (customer.email), one in a list with its place (components[0].term_years). Left out when the error isn't about particular inputs.

Example
{
  "error": {
    "code": "forbidden",
    "message": "origin 'https://www.example.com' is not allowlisted for this OAuth application"
  }
}

Get a product

GET https://subcontext.com/api/v1/products/{slug} Try it

Token scopes: read or write

One of your organisation's products, found by its slug.

Parameters

NameInTypeDescription
slug required path string

The product's slug, shown on its page in the dashboard under Products.

Responses

200 The product.

FieldTypeDescription
data required Product

A product, with the terms it's sold on now.

data.id required string (uuid)

The product's id.

data.display_id required string

The id as Subcontext shows it, prod_ and the id.

data.slug required string

The product's slug, used in addresses such as /api/v1/products/{slug}.

data.name required string

The product's name, as customers see it.

data.product_type required string

What kind of product it is.

One of: "term", "decreasing_term", "whole_of_life", "critical_illness", "income_protection", "bundled", "child_cover", "healthcare"
data.currency_code required string

The currency it's priced in (ISO 4217), such as GBP.

data.lifecycle_state required string

Where the product is in its life. Only production products are sold to the public.

One of: "draft", "sandbox", "production", "archived"
data.cooldown_days required integer

The cooling-off period, in days, during which a customer can cancel for a full refund.

data.inclusions required array of string

What the product includes, as short sentences for customers.

data.exclusions required array of string

What the product doesn't cover, as short sentences for customers.

data.cover_bounds required CoverBounds

The limits for a quote across all the product's covers: the lowest and highest amount, age at the start and term. Each is null when the product has no covers (or, for terms, no cover with a fixed term).

data.cover_bounds.sum_assured_min_pence required integer or null

The smallest amount of cover, in whole pence (the smallest unit of the product's currency).

data.cover_bounds.sum_assured_max_pence required integer or null

The largest amount of cover, in whole pence.

data.cover_bounds.age_min required integer or null

The youngest age, in years, at which cover can start.

data.cover_bounds.age_max required integer or null

The oldest age at which cover can start.

data.cover_bounds.term_min required integer or null

The shortest term, in years.

data.cover_bounds.term_max required integer or null

The longest term, in years.

data.covers required array of Cover

The covers that make up the product, such as life cover with critical illness cover added.

data.covers[].id required string (uuid)

The cover's id.

data.covers[].display_id required string

The id as Subcontext shows it, cov_ and the id.

data.covers[].cover_type required string

What the cover pays out for.

One of: "life", "critical_illness", "income_protection", "accidental_death", "child_benefit", "healthcare"
data.covers[].cover_index required integer

The cover's position in the product, starting at 0.

data.covers[].sum_assured_min_pence required integer

The smallest amount of cover, in whole pence (the smallest unit of the product's currency). For a monthly benefit, the yearly amount.

data.covers[].sum_assured_max_pence required integer

The largest amount of cover, in whole pence.

data.covers[].age_at_entry_min required integer

The youngest age, in years, at which this cover can start.

data.covers[].age_at_entry_max required integer

The oldest age at which this cover can start.

data.covers[].term_years_min required integer or null

The shortest term in years, or null for cover with no fixed term.

data.covers[].term_years_max required integer or null

The longest term in years, or null for cover with no fixed term.

data.covers[].max_age_at_expiry required integer or null

The oldest the person can be when the cover ends, if there's a limit.

data.covers[].premium_basis required string

Whether the price is fixed for the whole term (guaranteed) or reviewed from time to time (reviewable).

One of: "guaranteed", "reviewable"
data.covers[].review_period_years required integer or null

For reviewable premiums, how often in years the price is reviewed.

data.covers[].minimum_premium_pence required integer

The lowest monthly premium, in pence (or the smallest unit of the product's currency).

data.covers[].ci_payout_basis required string

For critical illness cover, whether it pays out on top of life cover (additional) or as an early part of it (accelerated).

One of: "additional", "accelerated"
data.covers[].survival_period_days required integer

How many days the person must survive after a diagnosis for a critical illness claim.

data.covers[].indexation_method required string

How the amount of cover changes over the term.

One of: "none", "rpi", "fixed_percent", "decreasing"
data.covers[].benefit_basis required string

Whether the cover pays a lump sum or a monthly benefit.

One of: "lump_sum", "monthly_benefit"
data.covers[].title required string or null

The cover's name where its type alone doesn't say which it is, such as one level of a group plan (Diagnosis); otherwise null.

data.covers[].pricing_basis required string

How the cover is priced: by underwriting and rate tables (rated), from a fixed list of cover levels, each with its own price (fixed_tiers), or at a monthly price for each person on it (per_member, an employer's group plan). A per-member cover has no amount of cover or term: its quote is sized by headcounts.

One of: "rated", "fixed_tiers", "per_member"
data.covers[].member_premium_pence required integer or null

For a per_member cover, the monthly price for each person on it, in whole pence; otherwise null.

data.covers[].members_factor required string or null

For a per_member cover, the key of the answer that holds how many people it covers, sent in risk_factors; otherwise null.

data.covers[].opt_in_factor required string or null

For a per_member add-on, the key of the yes or no answer that adds it to the plan (it then covers the number of people members_factor names); null for a cover that's always included, and for any other cover.

Example
{
  "data": {
    "id": "0199a3c2-5d1e-7b4a-9c3f-2e8d4b6a1f07",
    "display_id": "prod_0199a3c2-5d1e-7b4a-9c3f-2e8d4b6a1f07",
    "slug": "level-term-life",
    "name": "Level Term Life",
    "product_type": "term",
    "currency_code": "GBP",
    "lifecycle_state": "production",
    "cooldown_days": 30,
    "inclusions": [
      "Terminal illness benefit, paid early if you're diagnosed with 12 months or less to live"
    ],
    "exclusions": [
      "Death caused by a deliberately self-inflicted injury in the first year"
    ],
    "cover_bounds": {
      "sum_assured_min_pence": 1000000,
      "sum_assured_max_pence": 50000000,
      "age_min": 18,
      "age_max": 65,
      "term_min": 5,
      "term_max": 40
    },
    "covers": [
      {
        "id": "0199a3c2-5d1e-7b4a-9c3f-2e8d4b6a1f08",
        "display_id": "cov_0199a3c2-5d1e-7b4a-9c3f-2e8d4b6a1f08",
        "cover_type": "life",
        "cover_index": 0,
        "sum_assured_min_pence": 1000000,
        "sum_assured_max_pence": 50000000,
        "age_at_entry_min": 18,
        "age_at_entry_max": 65,
        "term_years_min": 5,
        "term_years_max": 40,
        "max_age_at_expiry": 80,
        "premium_basis": "guaranteed",
        "review_period_years": null,
        "minimum_premium_pence": 500,
        "ci_payout_basis": "additional",
        "survival_period_days": 14,
        "indexation_method": "none",
        "benefit_basis": "lump_sum",
        "title": null,
        "pricing_basis": "rated",
        "member_premium_pence": null,
        "members_factor": null,
        "opt_in_factor": null
      }
    ]
  }
}

401 No token was sent, or it isn't valid because it has expired, was revoked (for example because the application's secret was rotated), or was cut short. Get a new token and try once more.

FieldTypeDescription
error required object
error.code required string

A short code for the kind of error, such as invalid_token, forbidden, not_found or validation_failed. Each code means one thing wherever it appears.

error.message required string

What went wrong and what to do about it, in plain English.

error.fields object

When the error is about particular inputs, which ones and why, by name: a nested one with a dot (customer.email), one in a list with its place (components[0].term_years). Left out when the error isn't about particular inputs.

Example
{
  "error": {
    "code": "invalid_token",
    "message": "The access token has expired. Ask for a new one."
  }
}

403 The token can't be used here. It's missing a scope, it was used from the wrong place (a server-only application's token in a browser, or a browser application's token from a server, another website or a request only server-only applications may make), or it wasn't asked for with `resource=https://subcontext.com/api/v1`.

FieldTypeDescription
error required object
error.code required string

A short code for the kind of error, such as invalid_token, forbidden, not_found or validation_failed. Each code means one thing wherever it appears.

error.message required string

What went wrong and what to do about it, in plain English.

error.fields object

When the error is about particular inputs, which ones and why, by name: a nested one with a dot (customer.email), one in a list with its place (components[0].term_years). Left out when the error isn't about particular inputs.

Example
{
  "error": {
    "code": "forbidden",
    "message": "origin 'https://www.example.com' is not allowlisted for this OAuth application"
  }
}

404 There's no such record in your organisation.

FieldTypeDescription
error required object
error.code required string

A short code for the kind of error, such as invalid_token, forbidden, not_found or validation_failed. Each code means one thing wherever it appears.

error.message required string

What went wrong and what to do about it, in plain English.

error.fields object

When the error is about particular inputs, which ones and why, by name: a nested one with a dot (customer.email), one in a list with its place (components[0].term_years). Left out when the error isn't about particular inputs.

Example
{
  "error": {
    "code": "not_found",
    "message": "Resource not found"
  }
}

Stuck, or something missing?

Get in touch and a person on the team will help.

Contact us