API Reference (deprecated)

These endpoints have been deprecated. While they are are still suppported, we encourage you to check out our new API endpoints!

API requests use OAuth 2.0 bearer tokens over SSL, in the Authorization header (read through our authorization reference to find out how to get a token. See here for a list of supported scopes).
If you get a non-200 response, check this list of errors.

Your token gets genetic data from the customer who authorized it. If the "customer" was a demo account and not genotyped, you can still get mock genetic data (from two anonymous humans) by prepending /demo/ to most endpoints. For example:

curl https://api.23andme.com/1/user/ -H "Authorization: Bearer 081239h0f71hf" # customer's real data
curl https://api.23andme.com/1/demo/user/ -H "Authorization: Bearer 081239h0f71hf" # anonymized data

Endpoints

endpoint scope required example call and result
GET /1/user/
GET /1/demo/user/
Back To Top ↑
basic

email(opt)

Gets the user id, and a list of profiles (an account can have multiple genotyped people) with ids, whether or not they're genotyped.

The optional email parameter can be used to request the email for this account. Requires the "email" scope.

The optional services parameter can be used to request the endpoint to return what services are available to the profiles.

A service model object is made up of a unique service id, a service label, and a user-readable description of the service. All genotyped profiles should have "pgs_ancestry". Customers with access to health data will have "pgs_health". Demo profiles will have no services.

This endpoint is great for using an app anonymously because there is no personally identifying information.

curl https://api.23andme.com/1/user/ -H "..."
# JSON response:
{
    "id": "a42e94634e3f7683",
    "profiles": [
        {
            "genotyped": true,
            "id": "c4480ba411939067"
        }, ...
    ]
}

?services=true
# JSON response:
{
    "id": "a42e94634e3f7683",
    "profiles": [
        {
            "genotyped": true,
            "id": "c4480ba411939067",
            "services": [
                {
                    "description": "Health",
                    "label": "pgs_health",
                    "id": 1
                }, ...
            ]
        }, ...
    ]
}

?email=true w/ email scope
#JSON response:
{
    "id": "a42e94634e3f7683",
    "email": "gregormendel@23andme.com",
    "profiles": [
        {
            "genotyped": true,
            "id": "c4480ba411939067"
        }, ...
    ]
}
GET /1/names/profile_id/
GET /1/demo/names/profile_id/
Back To Top ↑
names For the user and user's profile, gets first and last names. If your user wants to remain anonymous, you shouldn't request this scope. You can optionally filter by profile_id to get the names for just that profile.
curl https://api.23andme.com/1/names/ -H "..."
# JSON response:
{
    "first_name": "Gregor",
    "last_name": "Mendel",
    "id": "a42e94634e3f7683",
    "profiles": [
        {
            "first_name": "Johann",
            "last_name": "Mendel",
            "id": "c4480ba411939067"
        }, ...
    ]
}
GET /1/profile_picture/profile_id/
POST /1/profile_picture/profile_id/
Back To Top ↑
We're no longer supporting this endpoint, please use the v3 profile endpoint
GET /1/genotypes/profile_id/?locations=&unfiltered=&format=...
GET /1/demo/genotypes/profile_id/?locations=&unfiltered=&format=...
Back To Top ↑
rsXX for each SNP requested, or genomes For the user's profile, returns the base-pairs, like AA, for the given locations. The value can have Ds or Is for deletions and insertions (for example, DD or DI). It can be __ if the customer is not on a chip that calls that location, or hasn't yet unlocked their call since it corresponds to a sensitive report. It can be -- if the customer is on a chip that calls that location, but we could not determine it. To keep consistency with the /genomes endoint, which always returns two base pairs, hemizygous calls (such as on X-linked genes in males) will also return two base pairs.

The scope of your token must include each location you request (i.e., getting the below data requires a scope of at least rs3094315 i3000001). This list of SNPs (44MB) shows which SNPs our customers are genotyped for.

The unfiltered parameter can be used for completely sex-unfiltered data.

The format parameter can be used to alter the JSON output format of this endpoint.

Since this is a GET endpoint, you may hit the browser-imposed URL limit with a lot of SNPs. We recommend splitting your requests into 100-SNP chunks.
curl https://api.23andme.com/1/genotypes/c44.../?locations=rs3094315%20i3000001 -H "..."
# JSON response:
{
    "i3000001": "II",
    "rs3094315": "AA"
    "id": "c4480ba411939067"
}

?format=embedded
# JSON response:
{
    "id": "c4480ba411939067"
    "genotypes": [
        {
            "location": "i3000001",
            "call": "II"
        },
        {
            "location": "rs3094315",
            "call": "AA"
        }
    ]
}
 
GET /1/phenotypes/profile_id/phenotype_id/
Back To Top ↑
phenotypes:read:<phenotype_id>

E.g. phenotypes:read:sex
For the user's profile, returns the requested phenotype. Which phenotypes can I get?
curl https://api.23andme.com/1/phenotypes/c44.../sex/
     -H "..."
# JSON response:
{
    "phenotype_id": "sex",
    "value": "male",
    "profile_id": "c4480ba411939067"
}
PUT /1/phenotypes/profile_id/phenotype_id/
Back To Top ↑
phenotypes:write:<phenotype_id>

E.g. phenotypes:write:date_of_birth
For the user's profile, sets the requested phenotype data. Which phenotypes can I get? The response will be identical to the GET so that you can verify the data is set properly.
curl -X PUT https://api.23andme.com/1/phenotypes/c44.../date_of_birth/
     -d "value=1976-06-30"
     -H "..."
# JSON response:
{
    "phenotype_id": "date_of_birth",
    "value": "1976-06-30",
    "profile_id": "c4480ba411939067"
}
GET /1/genomes/profile_id/
GET /1/demo/genomes/profile_id/
Back To Top ↑
genomes Returns the entire profile's genome as a packed string of base pairs "AACTGA...". This ~2MB request returns over a million SNP locations, so you must specify profile_id. See the /genotypes endpoint for possible values. Each SNP is represented with two base pairs, and to know which SNP corresponds to which index, see this key.

The endpoint may return a result with "status": "PENDING" and "genome": null due to internal caching. If this happens, the result should be ready in a few minutes.

When our genotyping chip is upgraded, the packed string and corresponding key will grow, but the changes will be backwards-compatible additions.
curl https://api.23andme.com/1/genomes/c44.../ -H "..."
# JSON response:
{
    "id": "c4480ba411939067",
    "genome": "ACTAGTAG__TTGADDAAIICCTT", # ... (2MB string!)
    "status": "READY"
}
# "Not ready" response:
{
    "id": "c4480ba411939067",
    "genome": null,
    "status": "PENDING"
}
 

About the unfiltered parameter

For the /genotypes endpoint, the optional parameter unfiltered returns raw calls from our probes. It's unlikely you'd need it, unless you want to perform your own biological sex checks, or are developing a sex-specific app such as a check for Klinefelter's Syndrome. Without the parameter, we filter out calls based on the genotype's sex, but if ?unfiltered=true, we will not filter:

  • Y calls for women
  • Heterozygous X calls for men on the non-pseudoautosomal region
  • Heterozygous mitochondrial calls

List of phenotypes you can get/set

For the /phenotypes read and write endpoints, your phenotype_id can be any of the following:

  • bd_pgen_patient_id: Participation in Harvard (HSPH) study of personal genomics (PGen)
  • date_of_birth: date of birth (YYYY-MM-DD)
  • family_tree_url: family tree url
  • height_mm: height in millimeters
  • sex: sex
  • weight_g: weight in grams