curl --request POST \
--url https://www.getprescience.com/api/partner/v1/quotes \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"company": {
"name": "Northwind Dental",
"domain": "northwinddental.com",
"external_id": "crd_4821",
"zip": "94110"
},
"census": [
{
"external_id": "emp_0001",
"first_name": "Ada",
"last_name": "Reyes",
"email": "ada@northwinddental.com",
"dob": "1991-04-02",
"zip": "94110"
}
]
}
'import requests
url = "https://www.getprescience.com/api/partner/v1/quotes"
payload = {
"company": {
"name": "Northwind Dental",
"domain": "northwinddental.com",
"external_id": "crd_4821",
"zip": "94110"
},
"census": [
{
"external_id": "emp_0001",
"first_name": "Ada",
"last_name": "Reyes",
"email": "ada@northwinddental.com",
"dob": "1991-04-02",
"zip": "94110"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
company: {
name: 'Northwind Dental',
domain: 'northwinddental.com',
external_id: 'crd_4821',
zip: '94110'
},
census: [
{
external_id: 'emp_0001',
first_name: 'Ada',
last_name: 'Reyes',
email: 'ada@northwinddental.com',
dob: '1991-04-02',
zip: '94110'
}
]
})
};
fetch('https://www.getprescience.com/api/partner/v1/quotes', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://www.getprescience.com/api/partner/v1/quotes",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'company' => [
'name' => 'Northwind Dental',
'domain' => 'northwinddental.com',
'external_id' => 'crd_4821',
'zip' => '94110'
],
'census' => [
[
'external_id' => 'emp_0001',
'first_name' => 'Ada',
'last_name' => 'Reyes',
'email' => 'ada@northwinddental.com',
'dob' => '1991-04-02',
'zip' => '94110'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://www.getprescience.com/api/partner/v1/quotes"
payload := strings.NewReader("{\n \"company\": {\n \"name\": \"Northwind Dental\",\n \"domain\": \"northwinddental.com\",\n \"external_id\": \"crd_4821\",\n \"zip\": \"94110\"\n },\n \"census\": [\n {\n \"external_id\": \"emp_0001\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Reyes\",\n \"email\": \"ada@northwinddental.com\",\n \"dob\": \"1991-04-02\",\n \"zip\": \"94110\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://www.getprescience.com/api/partner/v1/quotes")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"company\": {\n \"name\": \"Northwind Dental\",\n \"domain\": \"northwinddental.com\",\n \"external_id\": \"crd_4821\",\n \"zip\": \"94110\"\n },\n \"census\": [\n {\n \"external_id\": \"emp_0001\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Reyes\",\n \"email\": \"ada@northwinddental.com\",\n \"dob\": \"1991-04-02\",\n \"zip\": \"94110\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.getprescience.com/api/partner/v1/quotes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"company\": {\n \"name\": \"Northwind Dental\",\n \"domain\": \"northwinddental.com\",\n \"external_id\": \"crd_4821\",\n \"zip\": \"94110\"\n },\n \"census\": [\n {\n \"external_id\": \"emp_0001\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Reyes\",\n \"email\": \"ada@northwinddental.com\",\n \"dob\": \"1991-04-02\",\n \"zip\": \"94110\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"quote_id": "qt_5b9e2c7f10ad",
"status": "ready",
"group_id": "grp_8c2f41d09a3e",
"expires_at": "2026-11-01T17:22:05Z",
"plan_year_start_date": "2026-11-01",
"census": {
"employees": 3,
"covered_lives": 4
},
"plans": [
{
"id": "diamond",
"plan_name": "Prescience Diamond",
"status": "ready",
"monthly_premium_cents": 200000,
"pmpm_cents": 50000,
"rates_by_household": [
{
"label": "Employee only",
"households": 2,
"monthly_cents": 50000
},
{
"label": "Employee + 1",
"households": 1,
"monthly_cents": 100000
}
],
"deductible_cents": 0,
"oop_max_cents": 150000,
"max_extra_cents": 600000
},
{
"id": "value",
"plan_name": "Prescience Value",
"status": "ready",
"monthly_premium_cents": 160000,
"pmpm_cents": 40000,
"rates_by_household": [
{
"label": "Employee only",
"households": 2,
"monthly_cents": 40000
},
{
"label": "Employee + 1",
"households": 1,
"monthly_cents": 80000
}
],
"deductible_cents": 300000,
"oop_max_cents": 300000,
"max_extra_cents": 700000
}
]
}Pass a census, get a quote
Finds the group for the company (your group in the same mode with this company.external_id, else this company.domain, never an enrolled one) or creates it, replaces its census, and quotes. Prescience finds the plans in the group’s market itself; market_plans is no longer used. Returns 201 with the quote: Prescience Diamond and Prescience Value as numbers (add view=full for what each plan is), or 202 with retry_after_seconds while pricing runs (a few minutes for a new census): send the same body again. fields and exclude trim the response. Asking again with the same company, census and pricing run returns the quote already made; a changed census or a new pricing run makes a new quote.
curl --request POST \
--url https://www.getprescience.com/api/partner/v1/quotes \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"company": {
"name": "Northwind Dental",
"domain": "northwinddental.com",
"external_id": "crd_4821",
"zip": "94110"
},
"census": [
{
"external_id": "emp_0001",
"first_name": "Ada",
"last_name": "Reyes",
"email": "ada@northwinddental.com",
"dob": "1991-04-02",
"zip": "94110"
}
]
}
'import requests
url = "https://www.getprescience.com/api/partner/v1/quotes"
payload = {
"company": {
"name": "Northwind Dental",
"domain": "northwinddental.com",
"external_id": "crd_4821",
"zip": "94110"
},
"census": [
{
"external_id": "emp_0001",
"first_name": "Ada",
"last_name": "Reyes",
"email": "ada@northwinddental.com",
"dob": "1991-04-02",
"zip": "94110"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
company: {
name: 'Northwind Dental',
domain: 'northwinddental.com',
external_id: 'crd_4821',
zip: '94110'
},
census: [
{
external_id: 'emp_0001',
first_name: 'Ada',
last_name: 'Reyes',
email: 'ada@northwinddental.com',
dob: '1991-04-02',
zip: '94110'
}
]
})
};
fetch('https://www.getprescience.com/api/partner/v1/quotes', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://www.getprescience.com/api/partner/v1/quotes",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'company' => [
'name' => 'Northwind Dental',
'domain' => 'northwinddental.com',
'external_id' => 'crd_4821',
'zip' => '94110'
],
'census' => [
[
'external_id' => 'emp_0001',
'first_name' => 'Ada',
'last_name' => 'Reyes',
'email' => 'ada@northwinddental.com',
'dob' => '1991-04-02',
'zip' => '94110'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://www.getprescience.com/api/partner/v1/quotes"
payload := strings.NewReader("{\n \"company\": {\n \"name\": \"Northwind Dental\",\n \"domain\": \"northwinddental.com\",\n \"external_id\": \"crd_4821\",\n \"zip\": \"94110\"\n },\n \"census\": [\n {\n \"external_id\": \"emp_0001\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Reyes\",\n \"email\": \"ada@northwinddental.com\",\n \"dob\": \"1991-04-02\",\n \"zip\": \"94110\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://www.getprescience.com/api/partner/v1/quotes")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"company\": {\n \"name\": \"Northwind Dental\",\n \"domain\": \"northwinddental.com\",\n \"external_id\": \"crd_4821\",\n \"zip\": \"94110\"\n },\n \"census\": [\n {\n \"external_id\": \"emp_0001\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Reyes\",\n \"email\": \"ada@northwinddental.com\",\n \"dob\": \"1991-04-02\",\n \"zip\": \"94110\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://www.getprescience.com/api/partner/v1/quotes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"company\": {\n \"name\": \"Northwind Dental\",\n \"domain\": \"northwinddental.com\",\n \"external_id\": \"crd_4821\",\n \"zip\": \"94110\"\n },\n \"census\": [\n {\n \"external_id\": \"emp_0001\",\n \"first_name\": \"Ada\",\n \"last_name\": \"Reyes\",\n \"email\": \"ada@northwinddental.com\",\n \"dob\": \"1991-04-02\",\n \"zip\": \"94110\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"quote_id": "qt_5b9e2c7f10ad",
"status": "ready",
"group_id": "grp_8c2f41d09a3e",
"expires_at": "2026-11-01T17:22:05Z",
"plan_year_start_date": "2026-11-01",
"census": {
"employees": 3,
"covered_lives": 4
},
"plans": [
{
"id": "diamond",
"plan_name": "Prescience Diamond",
"status": "ready",
"monthly_premium_cents": 200000,
"pmpm_cents": 50000,
"rates_by_household": [
{
"label": "Employee only",
"households": 2,
"monthly_cents": 50000
},
{
"label": "Employee + 1",
"households": 1,
"monthly_cents": 100000
}
],
"deductible_cents": 0,
"oop_max_cents": 150000,
"max_extra_cents": 600000
},
{
"id": "value",
"plan_name": "Prescience Value",
"status": "ready",
"monthly_premium_cents": 160000,
"pmpm_cents": 40000,
"rates_by_household": [
{
"label": "Employee only",
"households": 2,
"monthly_cents": 40000
},
{
"label": "Employee + 1",
"households": 1,
"monthly_cents": 80000
}
],
"deductible_cents": 300000,
"oop_max_cents": 300000,
"max_extra_cents": 700000
}
]
}Authorizations
Partner API key. psk_test_<32 hex> for test mode, psk_live_<32 hex> for live mode. Store them in your secrets manager on issue. Live keys are shown once; the scoped partner portal can show an active sandbox key again.
Headers
Any non-empty string; deterministic keys from your own IDs work best. Repeating the same key with the same body on the same endpoint and mode within 24 hours returns the stored successful response (with Idempotent-Replay: true) instead of re-executing. Error responses are not stored.
Query Parameters
Broker keys only. numbers (the default) returns each plan's prices, deductible, out-of-pocket maximum and the most extra the company pays. full adds what each plan is: description, benefits, logos. Other partners always get the whole quote.
numbers, full Comma-separated fields to return, e.g. plans.pmpm_cents. Reach into the plans with plans.<field>. quote_id, group_id and status are always returned. Also accepted as fields in a POST body.
Comma-separated fields to leave out, e.g. plans.logos. Logo URLs do not change, so fetch them once, cache them and exclude them after. Also accepted as exclude in a POST body.
Body
Show child attributes
Show child attributes
Members, as in PUT /groups/{groupId}/census.
One employee record. Include dependent elections when your platform has them; submitted dependents drive covered lives and household tiers. When they are unavailable, Prescience uses a disclosed normalized small-group household mix for the preliminary model.
- Option 1
- Option 2
Show child attributes
Show child attributes
Plan design for the group. Optional; fields you send are set on the group, whether the request made it or found it.
Show child attributes
Show child attributes
The client's current plan: carrier, and pepm_cents for what it costs per employee per month (its renewal price if you have one). Optional. Each version then has vs_current_plan; the price is still set against the market.
Show child attributes
Show child attributes
When the quote is priced, your team's listed addresses get two emails: the materials to forward to the employer (each PDF attached) and a For you email with the quote, the client email draft and Presenting Prescience. Send false to turn both off for this group; the choice holds until you send it again.
No longer used: Prescience finds the plans itself. A request that sends it is priced the same way, and each plan is listed in ignored_plans. Send the client's current plan as current_coverage.
500Show child attributes
Show child attributes
As the view query parameter.
numbers, full As the fields query parameter, as a list.
["plans.pmpm_cents"]
As the exclude query parameter, as a list.
["plans.logos"]
Response
The quote: Diamond and Value as numbers, or with what each plan is when view=full.
The quote as a broker gets it: numbers only by default, and what each plan is with view=full.
ready, in_review, expired Show child attributes
Show child attributes
Quote-specific sales previews for employees and employers. Forwardable links include an interactive view and PDF. Pending group links become available when pricing completes; a changed census requires a new quote. Preview terms are subject to underwriting and enrollment. Links are omitted when signing is unavailable.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Plans you sent that were skipped, and why.
Show child attributes
Show child attributes