NAV
python python--octopod-wrapper shell shell--octopod-client

Overview

Welcome to the GalateaBio Ancestry API!

You can use our API to access GalateaBio Ancestry API endpoints.

Environment API URL
Prod https://api.galatea.bio/api/v1
Sandbox https://api.sandbox.galatea.bio/api/v1

API reference

References for API endpoints with descriptions and usage examples.

Recipes

Recipes for common operations.

API reference

GalateaBio Ancestry API endpoints.
API authorization endpoints

Method Endpoint Reference
POST users/auth Login
POST users/logout Logout
POST users/refresh Refresh token


API endpoints for working with user profile

Method Endpoint Reference
GET users/me Info about you and your organization


API endpoints for working with source and result files

Method Endpoint Reference
GET data/files List files
GET data/results/{order_id}/download Get result file
GET data/results/{order_id}/json Get result json
POST data/files/upload Upload file
DELETE data/files/{source_file_id} Delete file


API endpoints for working with execution orders

Method Endpoint Reference
GET exec/orders List orders
GET exec/orders?{params} Order details
POST exec/orders Submit order
PATCH exec/orders/{order_id} Update order
POST exec/cancel Cancel order
GET exec/tags List tags
GET exec/tags/{tag_id} Get tag
POST exec/tags Create tag
PUT exec/tags/{tag_id} Edit tag
DELETE exec/tags/{tag_id} Delete tag

Auth

GalateaBio Ancestry API Auth endpoints.

Method Endpoint Reference
POST users/auth Login
POST users/logout Logout
POST users/refresh Refresh token

POST users/auth

Use this code to obtain access token via API:

import requests

url = "https://api.dev.galatea.bio/api/v1/users/auth"

payload = {
    "email": "[email protected]",
    "password": "Your_password"
}
headers = {
    "content-type": "application/json",
    "accept": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
# authentication with API key
base_url = "https://api.dev.galatea.bio"
api_key = 'Octopod API Key'
octopod_client = OctopodClient(base_url=base_url, api_key=api_key)

# authentication with username and password
base_url = "https://api.dev.galatea.bio"
auth_json = OctopodClient.authenticate(
    username='[email protected]',
    password='Your_password',
    base_url=base_url,
)
api_key = auth_json.get('access')  # fetched api_key has short lifetime!
octopod_client = OctopodClient(base_url=base_url, api_key=api_key)
curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/users/auth' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "[email protected]",
    "password": "Your_password"
  }'
# authentication with API key
octo set-config \
--api_mode=1 \
--api_base_url="https://api.dev.galatea.bio" \
--api_key="<api_key>"

# authentication with username and password
octo set-config \
--api_mode=2 \
--api_base_url="https://api.dev.galatea.bio" \
--api_username="[email protected]" \
--api_password="Your_password"

Make sure to replace [email protected] and Your_password with your personal credentials.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "refresh": "refresh_token",
  "access": "access_token",
  "websocket_access": "websocket_access_token"
}

Endpoint for getting personal API access token.

POST users/logout

Use this code to logout via API:

import requests

url = "https://api.dev.galatea.bio/api/v1/users/logout"

payload = {
    "refresh": "<<refresh_token>>"
}
headers = {
    "content-type": "application/json",
    "accept": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/users/logout' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "refresh": "<<refresh_token>>"
}'

The above command returns HTTP CODE 200 on success logout.

Endpoint for log out, requires refresh_token from Authentication step.

POST users/refresh

Use this code to renew access and refresh tokens via API:

import requests

url = "https://api.dev.galatea.bio/api/v1/users/refresh"

payload = {
    "refresh": "<<refresh_token>>",
    "access": "<<access_token>>"
}
headers = {
    "content-type": "application/json",
    "accept": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/users/refresh' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "refresh": "<<refresh_token>>",
  "access": "<<access_token>>"
}'

The above command returns JSON:

{
  "refresh": "refresh_token",
  "access": "access_token"
}

Endpoint for renewing auth tokens, requires refresh_token from Authentication step.

Users

GalateaBio Ancestry API Users endpoints.

Method Endpoint Reference
GET users/me Info about you

GET users/me

Use this code to get information about your profile via API:

import requests

url = "https://api.dev.galatea.bio/api/v1/users/me"

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.get(url, headers=headers)

print(response.text)
octopod_client.organization_api.get_organization_info()
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1/users/me' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
octo get-organization-info

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "id": "11111111-1111-1111-1111-111111111111",
  "email": "[email protected]",
  "first_name": "First Name",
  "last_name": "Last Name",
  "role": "OrgUser",
  "is_active": true,
  "created_at": "2023-05-10T10:17:49.344128Z",
  "deleted_at": null,
  "updated_at": "2025-07-09T10:36:44.174576Z",
  "org": {
    "id": "12332112-3321-2233-1122-123432345648",
    "name": "Organization name",
    "domains": [
      "example.com",
      "example-second.com"
    ],
    "available_models": [
      "ancestry data model one",
      "ancestry data model two",
      "ancestry pdf model",
      "prs ruo model",
      "prs clinical model",
    ],
    "webhooks_enabled": true,
    "webhooks_secret": "e2Bib57PYkkTFCs7utEfSZd6yGZCmGYX",
    "report_ancestry_enabled": true,
    "report_prs_ruo_cardio_enabled": true,
    "report_prs_ruo_cancer_enabled": true,
    "report_prs_clinical_cardio_enabled": true,
    "report_prs_clinical_cancer_enabled": true
  }
}

Endpoint for getting information about your profile.
It includes information about your organization and available execution models.

Data

GalateaBio Ancestry API Data endpoints.

Method Endpoint Reference
GET data/files List files
GET data/results/{order_id}/download Get result file
GET data/results/{order_id}/json Get result json
GET data/results/{order_id}/pdf_report Get PDF reports list
POST data/files/upload Upload file
DELETE data/files/{source_file_id} Delete file

GET Source files

Use this code to get list of source files via API:

import requests
file_name = 'filename.txt.zip' # or file_id

url = f"https://api.dev.galatea.bio/api/v1/data/files?file={file_name}"
headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.get(url, headers=headers)
print(response.text)
file_name = 'filename.txt.zip' # or file_id
files_objs = octopod_client.file_api.list_files(**{'file': file_name})
if files_objs.get('count', 0) > 0:
    file_id = files_objs.get('results', [])[0].get('id')
    file_obj = octopod_client.file_api.find_file_by_id(file_id)
file_name='filename.txt.zip' # or file_id
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1/data/files?file=${file_name}' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
octo find-file --file_id="<file_id>"
octo find-file --file_name="<file_name>"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "count": 2,
  "next": "https://api.dev.galatea.bio/api/v1/data/files?page=2",
  "previous": null,
  "results": [
    {
      "id": "9085d0d2-3333-1111-2222-4114602c2aa6",
      "status": "VALID",
      "src_file_name": "filename.txt.zip",
      "src_short_file_path": "web-upload/2025-06-20-092716/filename.txt.zip",
      "file_size_bytes": 5795952,
      "created_at": "2025-06-20T09:27:17.344081Z",
      "check_sum": "feee6f11ade6b8b4ee28e12801211d07",
      "acceptable": true,
      "purged_from_storage": false,
      "orders_count": 0,
      "genome_type": "GNT",
      "amount_of_samples": 1,
      "deleted_at": null,
      "org_name": "Organization name",
      "check_completed": true,
      "sample_alias": null,
      "check_information": null,
      "virtual": false
    },
    {
      "id": "51f1ad10-1111-2222-3333-ddb50b37a40d",
      "status": "VALID",
      "src_file_name": "filename.txt.zip",
      "src_short_file_path": "web-upload/2025-07-14-103020/filename.txt.zip",
      "file_size_bytes": 34843764,
      "created_at": "2025-07-14T10:30:20.433081Z",
      "check_sum": "2b103756484ad1a5e691c756898b3310",
      "acceptable": true,
      "purged_from_storage": false,
      "orders_count": 0,
      "genome_type": "GNT",
      "amount_of_samples": 1,
      "deleted_at": null,
      "org_name": "Organization name",
      "check_completed": true,
      "sample_alias": null,
      "check_information": null,
      "virtual": false
    }
  ]
}

Endpoint for getting list of source files.

Optional query parameters:

Example:

https://api.dev.galatea.bio/api/v1/data/files?file=filename.txt.zip&only_acceptable=true

POST Upload file

Use this code to upload file via API:

import requests

url = "https://api.dev.galatea.bio/api/v1/data/files/upload"

headers = {
    'accept': 'application/json',
    'Authorization': 'Bearer <<access_token>>'
}

with open('filename.txt.zip', 'rb') as file_for_upload:
    response = requests.post(url, headers=headers, files={'file': file_for_upload})

print(response.text)
file_name = 'filename.txt.zip'
file_obj = octopod_client.file_api.upload_file(file_name)

# or

file_name = 'filename.txt.zip'
with open(file_name, "rb") as fh:
    buf = BytesIO(fh.read())
    file_obj = octopod_client.file_api.upload_file_from_io(buf, file_name)
curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/data/files/upload' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer ACCESS_TOKEN' \
  -H 'Content-Type: multipart/form-data' \
  -F '[email protected];type=application/x-zip-compressed'
full_file_name='/full/path/to/filename.txt.zip'
octo api-upload-file --file_name="${full_file_name}"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "id": "9085d0d2-3333-1111-2222-4114602c2aa6",
  "status": "PENDING",
  "src_file_name": "filename.txt.zip",
  "src_short_file_path": "web-upload/2025-07-16/075700/filename.txt.zip",
  "file_size_bytes": 5219426,
  "created_at": "2025-07-16T07:57:06.855150Z",
  "check_sum": "bba8c0456b0ad6e754eadbce921a7531",
  "acceptable": true,
  "purged_from_storage": false,
  "orders_count": 0,
  "genome_type": "GNT",
  "amount_of_samples": 0,
  "deleted_at": null,
  "org_name": "Organization name",
  "check_completed": false,
  "sample_alias": null,
  "check_information": null,
  "virtual": false
}

Endpoint for uploading source files.
With this endpoint can be uploaded files with size less than 50MB.

For uploading files more than 50MB use SFTP upload instruction.

If configured websocket notifications will be sent message with status when a file will be validated.
More information about using websocket notification

DELETE Source files

Use this code to delete source file via API:

import requests

source_file_id = '9085d0d2-3333-1111-2222-4114602c2aa6'
url = f'https://api.dev.galatea.bio/api/v1/data/files/{source_file_id}'

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.get(url, headers=headers)
print(response.status_code)
source_file_id = '9085d0d2-3333-1111-2222-4114602c2aa6'

octopod_client.file_api.delete_file(source_file_id)
curl -X 'DELETE' \
  'https://api.dev.galatea.bio/api/v1/data/files/9085d0d2-3333-1111-2222-4114602c2aa6' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
source_file_id='9085d0d2-3333-1111-2222-4114602c2aa6'
octo delete-file --file_id="${source_file_id}"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

Endpoint for deleting source files by file id.

GET Download results

Use access_token from Authentication step.
Instruction to Configure wrapper and client

Use order_id from Execution submit order endpoint.
or from Get orders

import requests
import shutil

order_id = '1234567d-1111-2222-3333-12345abcd123'
result_type = 'SUMMARY_CHROMS'

url = f'https://api.dev.galatea.bio/api/v1/data/results/{order_id}/download?result_type={result_type}'
headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.get(url, headers=headers, stream=True)
filename = response.headers['content-disposition'].split('; ')[1].split('=')[1].replace('"', '')

with open(filename, 'wb') as out_file:
    shutil.copyfileobj(response.raw, out_file)

print(response.status_code)

# single pdf report file
result_type = 'PDF_REPORT'
pdf_request_id = '11112222-1111-1111-1111-4f7992dea817'

url = f'https://api.dev.galatea.bio/api/v1/data/results/{order_id}/download?result_type={result_type}&pdf_request_id={pdf_request_id}'

response = requests.get(url, headers=headers, stream=True)
filename = response.headers['content-disposition'].split('; ')[1].split('=')[1].replace('"', '')

with open(filename, 'wb') as out_file:
    shutil.copyfileobj(response.raw, out_file)

print(response.status_code)
order_id = '1234567d-1111-2222-3333-12345abcd123'

result_type = 'SUMMARY_CHROMS'

result_file_content: BytesIO, result_file_name: str = octopod_client.result_api.download_result_file(
  order_id=order_id,
  result_type=result_type,
)

with open(result_file_name, "wb") as f:
    f.write(result_file_content.getbuffer())

# single pdf report file
result_type_reports = 'PDF_REPORT'
pdf_request_id = '11112222-1111-1111-1111-4f7992dea817'

result_file_content: BytesIO, result_file_name: str = octopod_client.result_api.download_result_file(
  order_id=order_id,
  result_type=result_type,
  pdf_request_id=pdf_request_id,
)

with open(result_file_name, "wb") as f:
    f.write(result_file_content.getbuffer())
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1data/results/1234567d-1111-2222-3333-12345abcd123/download?result_type=SUMMARY_CHROMS' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -o result_filename.tsv

# single pdf report file
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1data/results/1234567d-1111-2222-3333-12345abcd123/download?result_type=PDF_REPORT&pdf_request_id=11112222-1111-1111-1111-4f7992dea817' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -o result_filename.tsv
order_id='1234567d-1111-2222-3333-12345abcd123'
result_type="SUMMARY_CHROMS"
pdf_request_id=11112222-1111-1111-1111-4f7992dea817

octo download-result-file --order_id="${order_id}" --result_type="${result_type}"

# single pdf report file
octo download-result-file --order_id="${order_id}" --result_type=PDF_REPORT --pdf_request_id="${pdf_request_id}"

Endpoint for getting result files of an execution order or errors occured during execution.
List of available result types for downloading is shown in GET order details

Query parameters:

Results type Description
SUMMARY_CHROMS Summary set of chromosomes, tsv file
SUMMARY_SUPERSET Summary superset of labels, tsv file
DETAILED_CHROMS Detailed set of labels by chromosome
DETAILED_SUPERSET Detailed superset of labels by chromosome, zip archive
EXEC_ERRORS Execution errors, contains errors about data processing
PDF_REPORT All generated PDF reports in zip archive
PRS_JSON_DATA PRS data in json files per report type, zip archive
PRS_IMAGES PRS diagrams in png for high risk items, zip archive

Example:

https://api.dev.galatea.bio/api/v1/data/results/{order_id}/download?result_type=SUMMARY_CHROMS
https://api.dev.galatea.bio/api/v1/data/results/{order_id}/download?result_type=PDF_REPORT&pdf_request_id=11112222-1111-1111-1111-4f7992dea817

GET Result in json

Use this code to download result json via API:

import requests

order_id = '1234567d-1111-2222-3333-12345abcd123'
url = f'https://api.dev.galatea.bio/api/v1/data/results/{order_id}/json'

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.get(url, headers=headers)

print(response.text)
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1data/results/1234567d-1111-2222-3333-12345abcd123/json' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: multipart/form-data'

Use access_token from Authentication step.
Instruction to Configure wrapper and client

Use order_id from Execution orders endpoint.

Endpoint for getting result in JSON format, returns only results of type SUMMARY_CHROMS, SUMMARY_SUPERSET, DETAILED_CHROMS, DETAILED_SUPERSET.

GET list PDF reports

Use this code to get list of PDF reports available for order via API:

import requests
order_id = '1234567d-1111-2222-3333-12345abcd123'
url = "https://api.dev.galatea.bio/api/v1/data/results/{order_id}/pdf_report?page_size=1000"

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.get(url, headers=headers)
print(response.text)
order_id = '1234567d-1111-2222-3333-12345abcd123'

octopod_client.result_api.list_pdf_reports(order_id=order_id)
octopod_client.result_api.list_pdf_reports(order_id=order_id, request_version=2)
octopod_client.result_api.list_pdf_reports(order_id=order_id, sample_id="sandbox.34.4503157")
order_id='1234567d-1111-2222-3333-12345abcd123'
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1/data/results/{$order_id}/pdf_report?page_size=1000' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
order_id='1234567d-1111-2222-3333-12345abcd123'

octo list-result-pdf-reports --order_id="${order_id}"
octo list-result-pdf-reports --order_id="${order_id}" --request_version=2
octo list-result-pdf-reports --order_id="${order_id}" --sample_id="sandbox.34.4503157"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "count": 3,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "11112222-1111-1111-1111-4f7992dea817",
      "status": "COMPLETED",
      "sample_id": "sandbox.34.4503157",
      "order_id": "1234567d-1111-2222-3333-12345abcd123",
      "result_id": "22222222-2222-1111-1111-222222222222",
      "org_name": "Organization name",
      "request_type": "ORDER",
      "request_version": 1,
      "report_version": "GalaxyBio Vader 2024-Jan-01 11112222",
      "pdf_file_name": "11112222-1111-1111-1111-4f7992dea817_sandbox.34.4503157.pdf",
      "file_size_bytes": 3019238,
      "check_sum": "ee309c64c793995e91876817d47e9f02",
      "started_at": "2024-02-08T06:56:15.668489Z",
      "completed_at": "2024-02-08T06:57:37.515947Z"
    },
    {
      "id": "33333333-3333-3333-1111-c21745d2f1ac",
      "status": "COMPLETED",
      "sample_id": "sandbox.34.4503157",
      "order_id": "12312312-1111-2222-3333-456456456456",
      "result_id": "22222222-2222-1111-1111-22222222222",
      "org_name": "Organization name",
      "request_type": "SAMPLE",
      "request_version": 2,
      "report_version": "GalaxyBio Vader 2024-Mar-07 22223333",
      "pdf_file_name": "33333333-3333-3333-1111-c21745d2f1ac_sandbox.34.4503157.pdf",
      "file_size_bytes": 1935233,
      "check_sum": "0ae482fe89eb6d4b9f9b237a4d74a857",
      "started_at": "2024-03-08T06:56:15.652829Z",
      "completed_at": "2024-03-08T06:57:26.142578Z"
    }
  ]
}

Endpoint for getting list of PDF reports generated in execution order.
PDF reports can be downloaded individually or as a zip archive with all reports via Download result with result_type=PDF_REPORT

For downloading single pdf report file use additional parameter pdf_request_id with result_type=PDF_REPORT in Download result
https://api.dev.galatea.bio/api/v1/data/results/{order_id}/download?result_type=PDF_REPORT&pdf_request_id=33333333-3333-3333-1111-c21745d2f1ac

Optional query parameters:

Example:

Exec

GalateaBio Ancestry API Exec endpoints.

Method Endpoint Reference
GET exec/orders List orders
GET exec/orders?{params} Order details
POST exec/orders Submit order
PATCH exec/orders/{order_id} Update order
POST exec/cancel Cancel order
GET exec/tags List tags
GET exec/tags/{tag_id} Get tag
POST exec/tags Create tag
PUT exec/tags/{tag_id} Edit tag
DELETE exec/tags/{tag_id} Delete tag

GET exec/orders

Use this code to get list of orders via API:

import requests

# all orders without filtering
url = 'https://api.dev.galatea.bio/api/v1/exec/orders'

# orders by status group
status_group = 'completed'
url = f'https://api.dev.galatea.bio/api/v1/exec/orders?status_group={status_group}'

# orders filtered by tags
tag_ids='12312312-1111-4444-9999-456456456456,11111111-b183-4217-9b89-222222222222'
url = f'https://api.dev.galatea.bio/api/v1/exec/orders?tag_ids={tag_ids}'

headers = {
    'accept': 'application/json',
    'Authorization': 'Bearer <<access_token>>'
}

response = requests.get(url, headers=headers)

print(response.text)
# all orders without filtering
order_obj = octopod_client.order_api.list_orders()

# orders by status
status_group = 'completed'
order_obj = octopod_client.order_api.list_orders(status_group=status_group)

# orders filtered by tags
tag_ids='12312312-1111-4444-9999-456456456456,11111111-b183-4217-9b89-222222222222'
order_obj = octopod_client.order_api.list_orders(tag_ids=tag_ids)
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1/exec/orders' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
# use shell or python examples

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "count": 2,
  "next": "https://api.dev.galatea.bio/api/v1/exec/orders?page=2",
  "previous": null,
  "results": [
    {
      "id": "fc79a3e0-60db-452b-9fc4-506897b4f808",
      "status": "Completed",
      "src_file_id": "9085d0d2-3333-1111-2222-4114602c2444",
      "src_file_short_path": "somepath/filename.gvcf.gz",
      "src_file_name": "filename.gvcf.gz",
      "started_at": "2025-07-14T09:06:26.146529Z",
      "amount_of_samples": 1,
      "execution_time": 96.496678,
      "submitted_by": "[email protected]",
      "model": "prs ruo model",
      "type": "WGS",
      "org_name": "Organization name",
      "tags": [
        {
          "id": "12312312-1111-4444-9999-456456456456",
          "name": "test tag"
        }
      ],
      "result_types": [
        {
          "type": "SUMMARY_SUPERSET",
          "label": "Summary superset"
        },
        {
          "type": "DETAILED_SUPERSET",
          "label": "Detailed superset by chromosome"
        },
        {
          "type": "PRS_JSON_DATA",
          "label": "PRS json data zip"
        },
        {
          "type": "PRS_IMAGES",
          "label": "PRS images zip"
        },
        {
          "type": "PDF_REPORT",
          "label": "PDF reports zip"
        },
        {
          "type": "PDF_REPORT",
          "label": "View PDF reports"
        }
      ],
      "can_request_pdf": true,
      "virtual": false
    },
    {
      "id": "22233344-1111-2222-3333-555666777888",
      "status": "Completed",
      "src_file_id": "9085d0d2-3333-1111-2222-4114602c2aa6",
      "src_file_short_path": "web-upload/2025-02-20/012716/filename.txt.zip",
      "src_file_name": "filename.txt.zip",
      "started_at": "2025-06-21T08:27:20.133904Z",
      "amount_of_samples": 1,
      "execution_time": 112.13555,
      "submitted_by": "[email protected]",
      "model": "ancestry data model one",
      "type": "GNT",
      "org_name": "Organization name",
      "tags": [
        {
          "id": "12312312-b183-4217-9b89-456456456456",
          "name": "SANDBOX"
        }
      ],
      "result_types": [
        {
          "type": "SUMMARY_SUPERSET",
          "label": "Summary superset"
        },
        {
          "type": "DETAILED_SUPERSET",
          "label": "Detailed superset by chromosome"
        },
      ],
      "can_request_pdf": false,
      "virtual": false
    },
  ]
}

Endpoint for getting list of execution orders submitted by users related to your organization.
More datailed information for search in Order details

Optional query parameters:

Examples:

https://api.dev.galatea.bio/api/v1/exec/orders
https://api.dev.galatea.bio/api/v1/exec/orders?status_group=completed
https://api.dev.galatea.bio/api/v1/exec/orders?status=Completed
https://api.dev.galatea.bio/api/v1/exec/orders?tags_ids=12312312-1111-4444-9999-456456456456,11111111-b183-4217-9b89-222222222222

GET exec/orders?params

Use this code to get list of orders via API:

import requests

# by order_id
search_for = 'fc79a3e0-60db-452b-9fc4-506897b4f808'

# or by source file name
search_for = 'filename.gvcf.gz'

# or by source file id
search_for = '9085d0d2-3333-1111-2222-4114602c2444'

url = f'https://api.dev.galatea.bio/api/v1/exec/orders?filter={search_for}'

headers = {
    'accept': 'application/json',
    'Authorization': 'Bearer <<access_token>>'
}

response = requests.get(url, headers=headers)
print(response.text)
# by order_id
search_for = 'fc79a3e0-60db-452b-9fc4-506897b4f808'

# or by source file name
search_for = 'filename.gvcf.gz'

# or by source file id
search_for = '9085d0d2-3333-1111-2222-4114602c2444'

order_obj = octopod_client.order_api.find_order_by_id_or_file_id(search_for)
order_status = order_obj.get('status')
order_result_types = order_obj.get('result_types')
# by order_id
search_for='fc79a3e0-60db-452b-9fc4-506897b4f808'

# or by source file name
search_for='filename.gvcf.gz'

# or by source file id
search_for='9085d0d2-3333-1111-2222-4114602c2444'

curl -X 'GET' \
  "https://api.dev.galatea.bio/api/v1/exec/orders?filter=${search_for}" \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
# by order_id
search_for='fc79a3e0-60db-452b-9fc4-506897b4f808'

# or by source file name
search_for='filename.gvcf.gz'

# or by source file id
search_for='9085d0d2-3333-1111-2222-4114602c2444'

octo find-order --order_id_or_file_id="$search_for"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "count": 1,
  "next": "https://api.dev.galatea.bio/api/v1/exec/orders?page=2",
  "previous": null,
  "results": [
    {
      "id": "fc79a3e0-60db-452b-9fc4-506897b4f808",
      "status": "Completed",
      "src_file_id": "9085d0d2-3333-1111-2222-4114602c2444",
      "src_file_short_path": "somepath/filename.gvcf.gz",
      "src_file_name": "filename.gvcf.gz",
      "started_at": "2025-07-14T09:06:26.146529Z",
      "amount_of_samples": 1,
      "execution_time": 96.496678,
      "submitted_by": "[email protected]",
      "model": "prs ruo model",
      "type": "WGS",
      "org_name": "Organization name",
      "tags": [
        {
          "id": "12312312-1111-4444-9999-456456456456",
          "name": "test tag"
        }
      ],
      "result_types": [
        {
          "type": "SUMMARY_SUPERSET",
          "label": "Summary superset"
        },
        {
          "type": "DETAILED_SUPERSET",
          "label": "Detailed superset by chromosome"
        },
        {
          "type": "PRS_JSON_DATA",
          "label": "PRS json data zip"
        },
        {
          "type": "PRS_IMAGES",
          "label": "PRS images zip"
        },
        {
          "type": "PDF_REPORT",
          "label": "PDF reports zip"
        },
        {
          "type": "PDF_REPORT",
          "label": "View PDF reports"
        }
      ],
      "can_request_pdf": true,
      "virtual": false
    },
  ]
}

Endpoint for getting list of execution orders submitted by users related to your organization.

Optional query parameters:

Examples:

https://api.dev.galatea.bio/api/v1/exec/orders?filter=fc79a3e0-60db-452b-9fc4-506897b4f808
https://api.dev.galatea.bio/api/v1/exec/orders?filter=filename.gvcf.gz

POST exec/orders

Use this code to submit order via API:

import requests

url = 'https://api.dev.galatea.bio/api/v1/exec/orders'

payload = {
  "source_file_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "model_name": "ancestry data model one",
  "tags_ids": [
    "9085d0d2-3333-1111-2222-4114602c2aa6"
  ],
}

headers = {
    'accept': 'application/json',
    'Authorization": 'Bearer <<access_token>>'
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
source_file_id = '3fa85f64-5717-4562-b3fc-2c963f66afa6'
model_name = 'ancestry data model one'

order_obj = octopod_client.order_api.submit_order(file_id=source_file_id, model_name=model_name)
curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/exec/orders' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "source_file_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "model_name": "ancestry data model one",
  "tags_ids": ["9085d0d2-3333-1111-2222-4114602c2aa6"]
}'
source_file_id='3fa85f64-5717-4562-b3fc-2c963f66afa6'
model_name='ancestry data model one'

octo submit-order --file_id="${source_file_id}" --model="${model_name}"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

[
  {
    "id": "22334545-6ca1-4492-94b0-112345002211",
    "status": "Registered",
    "src_file_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "src_file_short_path": "web-upload/2023-09-20-092716/filename.txt.zip",
    "src_file_name": "filename.txt.zip",
    "started_at": "2023-09-25T08:45:38.652925Z",
    "amount_of_samples": 1,
    "submitted_by": "[email protected]",
    "model": "ancestry data model one",
    "type": "GNT",
    "org_name": "Organization name",
    "tags": []
  }
]

Endpoint for submitting execution order.

If configured websocket notifications will be sent message with status when execution order will be done.
More information about using websocket notification

More examples for submitting order:
Submit ancestry data order
Submit ancestry PDF order
Submit PRS PDF order

PATCH exec/orders/{order_id}

Use this code to update order tags via API:

import requests

order_id='22334545-6ca1-4492-94b0-112345002211'
url = f'https://api.dev.galatea.bio/api/v1/exec/orders/{order_id}'

payload = {
  "tags_ids": [
    "11111111-b183-4217-9b89-222222222222",
    "33333333-1111-2222-9b89-222222222222"
  ]
}

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.patch(url, json=payload, headers=headers)

print(response.text)
order_id = '22334545-6ca1-4492-94b0-112345002211'
tags_ids = ['11111111-b183-4217-9b89-222222222222', '33333333-1111-2222-9b89-222222222222']

order_obj = octopod_client.order_api.update_order_tags(order_id=order_id, tags_ids=tags_ids)
curl -X 'PATCH' \
  'https://api.dev.galatea.bio/api/v1/exec/orders/22334545-6ca1-4492-94b0-112345002211' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "tags_ids": [
    "11111111-b183-4217-9b89-222222222222",
    "33333333-1111-2222-9b89-222222222222"
  ]
}'
order_id='22334545-6ca1-4492-94b0-112345002211'
tags_ids='11111111-b183-4217-9b89-222222222222,33333333-1111-2222-9b89-222222222222'

octo update-order-tags --order_id="${order_id}" --tags_ids="${tags_ids}"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "id": "22334545-6ca1-4492-94b0-112345002211",
  "status": "Completed",
  "src_file_id": "9085d0d2-3333-1111-2222-4114602c2aa6",
    "src_file_short_path": "web-upload/2023-09-20-092716/filename.txt.zip",
    "src_file_name": "filename.txt.zip",
  "started_at": "2023-09-25T08:45:38.652925Z",
  "amount_of_samples": 1,
  "execution_time": 161.882115,
  "submitted_by": "[email protected]",
  "model": "ancestry data model one",
  "type": "GNT",
  "has_error_log": false,
  "org_name": "Organization name",
  "result_json": [
    {
      "details": "Download via result endpoint."
    }
  ],
  "tags": [
    {
      "id": "11111111-b183-4217-9b89-222222222222",
      "name": "SANDBOX"
    },
    {
      "id": "33333333-1111-2222-9b89-222222222222",
      "name": "SANDBOX test"
    }
  ],
  "result_types": [
    "DETAILED_CHROMS",
    "SUMMARY_CHROMS"
  ]
}

Endpoint for updating execution order's tags.
Order can be updated with tags at any time.

POST exec/cancel

Use this code to Cancel submitted order via API:

import requests

url = "https://api.dev.galatea.bio/api/v1/exec/cancel"

payload = {
    "order_id": "22334545-6ca1-4492-94b0-112345002211"
}

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
order_id = '22334545-6ca1-4492-94b0-112345002211'

octopod_client.order_api.cancel_order(order_id=order_id)
curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/exec/cancel' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "order_id": "22334545-6ca1-4492-94b0-112345002211"
}'
order_id='22334545-6ca1-4492-94b0-112345002211'

octo cancel-order --order_id="${order_id}"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "details": "Request to cancel execution id 22334545-6ca1-4492-94b0-112345002211 accepted"
}

Endpoint for cancelling submited execution order.

Note: It is possible to cancel only orders in Registered and Submitted status.

GET exec/tags

Use this code to get list of execution tags via API:

import requests

# list all tags
url = 'https://api.dev.galatea.bio/api/v1/exec/tags'

# filter by name
url = 'https://api.dev.galatea.bio/api/v1/exec/tags?name=tag-name'

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.get(url, headers=headers)

print(response.text)
# list all tags
octopod_client.tag_api.list_tags()

# filter by name
octopod_client.tag_api.list_tags(name="tag-name")
# list all tags
url = 'https://api.dev.galatea.bio/api/v1/exec/tags'

# filter by name
url = 'https://api.dev.galatea.bio/api/v1/exec/tags?name=tag-name'

curl -X 'GET' \
  "${url}" \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
# list all tags
octo list-tags

# filter by name
octo list-tags --name="tag-name"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "count": 2,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "11111111-711a-4027-bc6b-111111111111",
      "name": "Demo",
      "org_id": "12332112-3321-2233-1122-123432345648"
    },
    {
      "id": "11111111-b183-4217-9b89-222222222222",
      "name": "SANDBOX",
      "org_id": "12332112-3321-2233-1122-123432345648"
    }
  ]
}

Endpoint for getting list of execution tags created by users realted to your organization.

Optional query parameters:

Examples:

https://api.dev.galatea.bio/api/v1/exec/tags?name=Demo

GET exec/tags/{tag_id}

Use this code to get execution Tag by tag id via API:

import requests

tag_id = '11111111-b183-4217-9b89-222222222222'
url = f'https://api.dev.galatea.bio/api/v1/exec/tags/{tag_id}'

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.get(url, headers=headers)

print(response.text)
tag_id = '11111111-b183-4217-9b89-222222222222'

octopod_client.tag_api.get_tag_by_id(tag_id=tag_id)
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1/exec/tags/11111111-b183-4217-9b89-222222222222' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
tag_id='11111111-b183-4217-9b89-222222222222'

octo find-tag --tag_id="${tag_id}"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "id": "11111111-b183-4217-9b89-222222222222",
  "name": "SANDBOX",
  "org_id": "12332112-3321-2233-1122-123432345648"
}

Endpoint for getting execution tag by tag_id related to your organization.

POST exec/tags

Use this code to create new execution Tag via API:

import requests

url = 'https://api.dev.galatea.bio/api/v1/exec/tags'

payload = {
  "name": "Demo Tag"
}

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
tag_name = 'Demo Tag'

octopod_client.tag_api.create_tag(name=tag_name)
curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/exec/tags' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Demo Tag"
}'
tag_name='Demo Tag'

octo create-tag --name="${tag_name}"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "id": "11111111-711a-4027-bc6b-111111111111",
  "name": "Demo Tag",
  "org_id": "12332112-3321-2233-1122-123432345648"
}

Endpoint for creating new execution Tag.

PUT exec/tags/{tag_id}

Use this code to edit execution Tag via API:

import requests

tag_id = '11111111-711a-4027-bc6b-111111111111'
new_tag_name = 'Demo Test Tag'
url = f'https://api.dev.galatea.bio/api/v1/exec/tags/{tag_id}'

payload = {
  "name": new_tag_name
}

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.put(url, json=payload, headers=headers)

print(response.text)
tag_id = '11111111-711a-4027-bc6b-111111111111'
new_tag_name = 'Demo Test Tag'

octopod_client.tag_api.update_tag(tag_id=tag_id, new_name=new_tag_name)
curl -X 'PUT' \
  'https://api.dev.galatea.bio/api/v1/exec/tags/11111111-711a-4027-bc6b-111111111111' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Demo Test Tag"
}'
tag_id='11111111-711a-4027-bc6b-111111111111'
new_tag_name='Demo Test Tag'

octo update-tag --tag_id="${tag_id}" --name="${new_tag_name}"

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "id": "11111111-711a-4027-bc6b-111111111111",
  "name": "Demo Test Tag",
  "org_id": "12332112-3321-2233-1122-123432345648"
}

Endpoint for edit execution Tag.

DELETE exec/tags/{tag_id}

Use this code to edit execution Tag via API:

import requests

tag_id = '11111111-711a-4027-bc6b-111111111111'
url = f'https://api.dev.galatea.bio/api/v1/exec/tags/{tag_id}'

headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.delete(url, headers=headers)

print(response.status_code)
# use python or shell code
curl -X 'DELETE' \
  'https://api.dev.galatea.bio/api/v1/exec/tags/11111111-711a-4027-bc6b-111111111111' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
# use python or shell code

Use access_token from Authentication step.
Instruction to Configure wrapper and client

The above command returns status:

200

Endpoint for edit execution Tag.

Recipes

Recipes for Galatea ancestry API usage.

Authentication

To get authorization token, use this code:

import requests

url = "https://api.dev.galatea.bio/api/v1/api/v1/users/auth"

payload = {
    'email': '[email protected]',
    'password': 'Your password'
}
headers = {
    'content-type': 'application/json',
    'accept': 'application/json'
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)

access_token = json.loads(response.text)['access']
auth_token = f'Bearer {access_token}'
# authentication with API key
base_url = "https://api.dev.galatea.bio"
api_key = 'Octopod-API-Key'
octopod_client = OctopodClient(base_url=base_url, api_key=api_key)

# authentication with username and password
base_url = "https://api.dev.galatea.bio"
auth_json = OctopodClient.authenticate(
    username='[email protected]',
    password='Your_password',
    base_url=base_url,
)
api_key = auth_json.get('access')  # fetched api_key has short lifetime!
octopod_client = OctopodClient(base_url=base_url, api_key=api_key)
curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/api/v1/users/auth' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
    "email": "[email protected]",
    "password": "Your password"
  }'
# authentication with API key
octo set-config \
--api_mode=1 \
--api_base_url="https://api.dev.galatea.bio" \
--api_key="<Octopod-API-Key>"

# authentication with username and password
octo set-config \
--api_mode=2 \
--api_base_url="https://api.dev.galatea.bio" \
--api_username="[email protected]" \
--api_password="Your_password"

Replace [email protected] and Your password with your personal credentials.
Instruction to Configure wrapper and client

The above command returns JSON:

{
  "refresh": "refresh_token",
  "access": "access_token",
  "websocket_access": "websocket_access_token"
}

GalateaBio Ancestry API uses personal access_token to allow access to the API.
GalateaBio Ancestry API requires authorization, API expects for the access_token included to all requests to API in a header:
Authorization: Bearer access_token

Install and configure octopod wrapper and client

# using PyPI
pip install galatea-cli

# using github repo
git clone https://github.com/GalateaBio/octopod-cli
pip install octopod file://octopod-cli

# authentication with API key
base_url = "https://api.dev.galatea.bio"
api_key = 'Octopod-API-Key'
octopod_client = OctopodClient(base_url=base_url, api_key=api_key)

# authentication with username and password
base_url = "https://api.dev.galatea.bio"
username = '[email protected]'
password = 'Your_password'

from octopod import OctopodClient

# fetched access_token has short lifetime!
auth_json = OctopodClient.authenticate(
    base_url=base_url,
    username=username,
    password=password,
)
access_token = auth_json.get('access')

octopod_client = OctopodClient(base_url=base_url, api_key=access_token)
# using PyPI
pip install galatea-cli

# using github repo
git clone https://github.com/GalateaBio/octopod-cli
pip install octopod file://octopod-cli

# authentication with API key
base_url = "https://api.dev.galatea.bio"
api_key = 'Octopod-API-Key'
octopod_client = OctopodClient(base_url=base_url, api_key=api_key)

# authentication with username and password
base_url = "https://api.dev.galatea.bio"
username = '[email protected]'
password = 'Your_password'

from octopod import OctopodClient

# fetched access_token has short lifetime!
auth_json = OctopodClient.authenticate(
    base_url=base_url,
    username=username,
    password=password,
)
access_token = auth_json.get('access')

octopod_client = OctopodClient(base_url=base_url, api_key=access_token)
# using PyPI
pip install galatea-cli

# using github repo
git clone https://github.com/GalateaBio/octopod-cli
pip install octopod file://octopod-cli

# authentication with API key
base_url="https://api.dev.galatea.bio"
api_key="Octopod-API-Key"

octo set-config \
--api_mode=1 \
--api_base_url="${base_url}" \
--api_key="${api_key}"

# authentication with username and password
base_url="https://api.dev.galatea.bio"
username='[email protected]'
password='Your_password'

octo set-config \
--api_mode=2 \
--api_base_url="${base_url}" \
--api_username="${username}" \
--api_password="${password}"

# to check and review config
octo get-config
# using PyPI
pip install galatea-cli

# using github repo
git clone https://github.com/GalateaBio/octopod-cli
pip install octopod file://octopod-cli

# authentication with API key
base_url="https://api.dev.galatea.bio"
api_key="Octopod-API-Key"

octo set-config \
--api_mode=1 \
--api_base_url="${base_url}" \
--api_key="${api_key}"

# authentication with username and password
base_url="https://api.dev.galatea.bio"
username='[email protected]'
password='Your_password'

octo set-config \
--api_mode=2 \
--api_base_url="${base_url}" \
--api_username="${username}" \
--api_password="${password}"

# to check and review config
octo get-config

For working with GalateaBio API are available 'octopod wrapper' and 'octopod client'.

Requirements:

Content:
GalateaBio Octopod client includes python lib and shell client to work with GalateaBio Ancestry API.

Installation:

Initial configuration:
Authentication can be made with api-key or with user credentials.
Authentication with user credentials is optional and providing short time access_token.
For correct working with GalateaBio API it is recommended to use api-key.

Octopod-client config

octo set-config

parameter description
--api_mode=1 mode 1 - using API key, mode 2 - login and password
--api_key="api_key" auth api key, using with api_mode=1
--api_username="user_username" user login, using with api_mode=2
--api_password="user_password" user password, using with api_mode=2
--api_base_url="api_base_url" Galatea Ancestry API url
--sftp_host="sftp_host" Galatea Ancestry API sftp host
--sftp_user="sftp_user" sftp user
--sftp_keyfile="/path/sftp_keyfile" path to ssh key file
--download_folder="/some/path" folder for storing downloaded files, if not set files will be stored in current path

Upload file

Supported 2 types of upload:
- using API for web upload files less than 50MB;
- using SFTP for all files;

Upload file with API and check status

Step 1. Use access_token from Authentication step.
Instruction to Configure wrapper and client

Step 2. Upload file less than 50MB

url_api = 'https://api.dev.galatea.bio/api/v1'
url_upload = f'{url_api}/data/files/upload'

headers = {
    'accept': 'application/json',
    'Authorization':  Bearer <<access_token>>
}

with open('filename.txt.zip', 'rb') as file_for_upload:
    response = requests.post(url_upload, headers=headers, files={'file': file_for_upload})

file_id = json.loads(response.text)['id']
file_name = 'filename.txt.zip'
file_obj = octopod_client.file_api.upload_file(file_name)

# or

file_name = 'filename.txt.zip'
with open(file_name, "rb") as fh:
    buf = BytesIO(fh.read())
    file_obj = octopod_client.file_api.upload_file_from_io(buf, file_name)
# For uploading file use auth_token from previous step.

curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/data/files/upload' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: multipart/form-data' \
  -F '[email protected];type=application/x-zip-compressed'
full_file_name='/full/path/to/filename.txt.zip'
octo api-upload-file --file_name="${full_file_name}"

JSON response:

{
  "id": "9085d0d2-3333-1111-2222-4114602c2aa6",
  "status": "PENDING",
  "src_file_name": "filename.txt.zip",
  "src_short_file_path": "web-upload/2025-07-16/075700/filename.txt.zip",
  "file_size_bytes": 5219426,
  "created_at": "2025-07-16T07:57:06.855150Z",
  "check_sum": "bba8c0456b0ad6e754eadbce921a7531",
  "acceptable": true,
  "purged_from_storage": false,
  "orders_count": 0,
  "genome_type": "GNT",
  "amount_of_samples": 0,
  "deleted_at": null,
  "org_name": "Organization name",
  "check_completed": false,
  "sample_alias": null,
  "check_information": null,
  "virtual": false
}

Step 3. Wait 2-5 minutes for completing validation before checking the file status.
Use file id from results in previous step.

url_api = 'https://api.dev.galatea.bio/api/v1'
url_get = f'{url_api}/data/files?file={file_id}'
response = requests.get(url_get, headers=headers)

if len(json.loads(response.text)['results']) == 1:
    status: bool = json.loads(response.text)['results'][0]['status']
    if status == 'PENDING':
        print('File registered, waiting for validation, check status in 30-60 seconds.')
    if status == 'VALID':
        print('File is valid, order can be submitted.')
    if status in ['NOT_VALID', 'FAILED']:
      print('File is not valid.')
      print(f'Errors: {json.loads(response.text)['results'][0]['check_information']}')
else:
    print('No such file on the server.')
file_obj = octopod_client.file_api.find_file_by_id(file_id)
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1/data/files?file={file_id}' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer ACCESS_TOKEN' \
octo find-file --file_id="<file_id>"

JSON response:

{
  "count":1,
  "next":null,
  "previous":null,
  "results":[
    {
      "id": "9085d0d2-3333-1111-2222-4114602c2aa6",
      "status": "VALID",
      "src_file_name": "filename.txt.zip",
      "src_short_file_path": "web-upload/2025-07-16/075700/filename.txt.zip",
      "file_size_bytes": 5219426,
      "created_at": "2025-07-16T07:57:06.855150Z",
      "check_sum": "bba8c0456b0ad6e754eadbce921a7531",
      "acceptable":true,
      "purged_from_storage":false,
      "orders_count":0,
      "genome_type":"GNT",
      "amount_of_samples":1,
      "deleted_at":null,
      "org_name":"Organization name",
      "check_completed":true,
      "sample_alias":null,
      "check_information":null,
      "virtual":false
    }
  ]
}

All uploaded files go through validation.
Execution order can be submitted only for sucessfully validated files with status VALID.
Validation takes up to 2-5 minutes.

Web upload for files with size less than 50MB:

  1. Authorize.
    Note: with using API-keys periodical authentication for obtaining token is not needed.

  2. Upload a file.
    Files with size less than 50MB can be uploaded with API.
    All other files can be uploaded with SFTP.

  3. Wait 2-5 minutes and check file status.
    On validation it checks file has correct name and correct content and can be accepted for executing order.
    On this step we cannot check that data in file is correct.

Alternatively to Step 3 can be configured websocket notifications.
Once a file will be validated will be sent a message with file info:
- new_status: VALID or FAILED
- source_file_id
- source_file_name

Upload file with SFTP and check status

Instruction to Configure wrapper and client
Connect to SFTP and upload a file

import paramiko as paramiko

ssh_client = paramiko.SSHClient()
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

sftp_host = 'sftp.dev.galatea.bio'
sftp_user = 'sftp-user-5c9a4f01'
ssh_key_file = '~/.ssh/id_rsa_private_sftp-user-5c9a4f01'

ssh_client.connect(hostname=sftp_host, username=sftp_user key_filename=ssh_key_file)

sftp_client = ssh_client.open_sftp()

# Create folder for uploading files
sftp.mkdir('2025-Feb-27')

# Upload file to created folder
file_name = 'd101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
remote_file_name = 'd101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'

sftp.chdir('2025-Feb-27')
sftp.put(file_name, remote_file_name)
sftp_host = 'sftp.dev.galatea.bio'
sftp_user = 'sftp-user-5c9a4f01'
ssh_key_file = '~/.ssh/id_rsa_private_sftp-user-5c9a4f01'

sftp_octopod_client = OctopodSftpClient(
  sftp_host=sftp_host,
  sftp_user=sftp_user,
  sftp_password=None,
  sftp_keyfile=ssh_key_file,
)

file_name = 'd101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
remote_file_name = 'd101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
remote_folder = '2025-Feb-27'

uploaded_path_file: str  = sftp_octopod_client.upload_file(
  file_name=file_name,
  remote_filename=remote_file_name,
  remote_folder=remote_folder,
)
sftp_host='sftp.dev.galatea.bio'
sftp_user='sftp-user-5c9a4f01'
ssh_key_file='~/.ssh/id_rsa_private_sftp-user-5c9a4f01'

$ sftp -i $ssh_key_file $sftp_user@$sftp_host

# Create folder for uploading files
$ sftp> mkdir 2025-Feb-27
$ sftp> cd 2025-Feb-27

# Upload file to created folder
$ sftp> put d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz

Uploading d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz to /2025-Feb-27/d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz
d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz                                  100%  525MB   4.6MB/s   00:05

# or single command with already created folder
$ sftp -i $ssh_key_file $sftp_user@$sftp_host>:/2025-Feb-27/ <<< $'put d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
sftp_host='sftp.dev.galatea.bio'
sftp_user='sftp-user-5c9a4f01'
ssh_key_file='~/.ssh/id_rsa_private_sftp-user-5c9a4f01'

# set config for sftp
octo set-config
--sftp_host="${sftp_host}"
--sftp_user="${sftp_user}"
--sftp_keyfile="${ssh_key_file}"

# upload file
file_name = 'd101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
remote_file_name = 'd101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
remote_folder = '2025-Feb-27'

octo sftp-upload-file --file_name="${file_name}" --remote_folder="${remote_folder}" --remote_file_name="${remote_file_name}"

Wait 2-3 minutes while file will be registered in the system.

file_name = 'd101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
url_get = f'{url_api}/data/files?file={file_name}'
response = requests.get(url_get, headers=headers)

if len(json.loads(response.text)['results']) == 1:
    status: bool = json.loads(response.text)['results'][0]['status']
    if status == 'PENDING':
        print('File registered, waiting for validation, check status in 30-60 seconds.')
    if status == 'VALID':
        print('File is valid, order can be submitted.')
    if status in ['NOT_VALID', 'FAILED']:
      print('File is not valid.')
      print(f'Errors: {json.loads(response.text)['results'][0]['check_information']}')
else:
    print('No such file on the server.')
file_name = 'd101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
files_objs = octopod_client.file_api.list_files(**{'file': file_name})
if files_objs.get('count', 0) > 0:
    file_id = files_objs.get('results', [])[0].get('id')
    file_obj = octopod_client.file_api.find_file_by_id(file_id)
file_name='d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
curl -X 'GET' \
  "https://api.dev.galatea.bio/api/v1/data/files?file=${file_name}" \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
file_name='d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz'
octo find-file --file_name="${file_name}"

Returned JSON response

{
  "count":1,
  "next":null,
  "previous":null,
  "results":[
    {
      "id":"7e53320c-c631-45ec-bad6-c88bb9d30960",
      "src_file_name":"d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz",
      "src_short_file_path":"2025-Feb-27/d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz",
      "file_size_bytes":26708788,
      "created_at":"2025-02-27T07:49:01.278404Z",
      "check_sum":"116e0f98dcda9666723e17b7d4aef490-6",
      "acceptable":true,
      "purged_from_storage":false,
      "orders_count":0,
      "genome_type":"GNT",
      "amount_of_samples":0,
      "deleted_at":null,
      "org_name":"Organization name",
      "check_completed":false,
      "sample_alias":null,
      "check_information":null,
      "status":"PENDING",
      "virtual":false
    }
  ]
}

All uploaded files go through validation.
Execution order can be submitted only for sucessfully validated files with status VALID.
Validation takes up to 2-5 minutes.

  1. Contact GalateaBio admins to obtain SFTP user and ssh keys and parameters for connection.
  2. Upload file via any sftp or scp client. Common recommendations:
    • use folders by date (2025-Feb-01) instead of uploading into root folder;
    • try to set unique name for files like uuid key.
  3. Wait 2-5 minutes.
  4. List files with filter by file name.
  5. Check file status.

Steps 3, 4, 5 can be skipped if websocket notifications is configured.
Once a file will be validated will be sent a message with file info:
- new_status: VALID or FAILED
- source_file_id
- source_file_name

Submit order

Submit execution order.

Ancestry data order

Use access_token from Authentication step.
Instruction to Configure wrapper and client

Submit execution order using source_file_id and model name.

url_api = 'https://api.dev.galatea.bio/api/v1'
url_orders = f'{url_api}/exec/orders'

payload = {
    'source_file_id': source_file_id,
    'model_name': 'ancestry data model one',
    'tags_ids': ['9085d0d2-3333-1111-2222-4114602c2aa6']
}

headers = {
    'accept': 'application/json',
    'Authorization': auth_token
}

response = requests.post(url_orders, json=payload, headers=headers)

print(response.text)
source_file_id = '3fa85f64-5717-4562-b3fc-2c963f66afa6'
model_name = 'ancestry data model one'
tags_ids = ['9085d0d2-3333-1111-2222-4114602c2aa6']

order_obj = octopod_client.order_api.submit_order(file_id=source_file_id, model_name=model_name, tags_ids=tags_ids)
source_file_id="3fa85f64-5717-4562-b3fc-2c963f66afa6"
model_name="ancestry data model one"

curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/exec/orders' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "source_file_id": "${source_file_id}",
  "model_name": "${model_name}",
  "tags_ids": ["9085d0d2-3333-1111-2222-4114602c2aa6"]
}'
source_file_id="3fa85f64-5717-4562-b3fc-2c963f66afa6"
model_name="ancestry data model one"
tags_ids='9085d0d2-3333-1111-2222-4114602c2aa6,12345672-1111-2222-3333-456789012345'

octo submit-order --file_id="${source_file_id}" --model="${model_name}" --tags_ids="${tags_ids}"

Response

{
  "id": "1234567d-1111-2222-3333-12345abcd123",
  "amount_of_samples": 1,
  "model": "ancestry data model one",
  "org_name": "your org name",
  "src_file_id": "b91dc168-5720-4f04-911f-a1c5aa14606d",
  "src_file_name": "filename.txt.zip",
  "src_file_short_path": "web_upload/2023-09-25/filename.txt.zip",
  "status": "Registered",
  "started_at": "2023-09-25T08:38:46.649136Z",
  "submitted_by": "your@email",
  "tags": [],
  "type": "GNT"
}

Submit execution order with model without reports.
All available models for your organization can be get in about me

Model API without report generation

Possible results Description
SUMMARY_CHROMS Summary set of chromosomes, tsv file
SUMMARY_SUPERSET Summary superset of labels, tsv file
DETAILED_CHROMS Detailed set of labels by chromosome
DETAILED_SUPERSET Detailed superset of labels by chromosome, zip archive
EXEC_ERRORS Execution errors, contains errors about data processing

Payload fields:

Payload example:
{
'source_file_id': source_file_id,
'model_name': 'ancestry data model one',
'tags_ids': ['9085d0d2-3333-1111-2222-4114602c2aa6']
}

Ancestry PDF order

Use access_token from Authentication step.
Instruction to Configure wrapper and client

Submit execution order using source_file_id and model name.

url_api = 'https://api.dev.galatea.bio/api/v1'
url_orders = f'{url_api}/exec/orders'

payload = {
    'source_file_id': source_file_id,
    'model_name': 'ancestry pdf model',
    'tags_ids': ['9085d0d2-3333-1111-2222-4114602c2aa6'],
    'pdf_metadata': {'patient_name': 'Patient Name'},
}

headers = {
    'accept': 'application/json',
    'Authorization': auth_token
}

response = requests.post(url_orders, json=payload, headers=headers)

print(response.text)
source_file_id = '3fa85f64-5717-4562-b3fc-2c963f66afa6'
model_name = 'ancestry pdf model'
tags_ids = ['9085d0d2-3333-1111-2222-4114602c2aa6']
pdf_metadata = {'patient_name': 'Patient Name'}

order_obj = octopod_client.order_api.submit_order(
    file_id=source_file_id,
    model_name=model_name,
    tags_ids=tags_ids,
    pdf_metadata=pdf_metadata,
)
source_file_id="3fa85f64-5717-4562-b3fc-2c963f66afa6"
model_name="ancestry pdf model"
pdf_metadata="{\"patient_name\": \"Patient Name\"}"

curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/exec/orders' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "source_file_id": "${source_file_id}",
  "model_name": "${model_name}",
  "tags_ids": ["9085d0d2-3333-1111-2222-4114602c2aa6"],
  "pdf_metadata": "${pdf_metadata}"
}'
source_file_id="3fa85f64-5717-4562-b3fc-2c963f66afa6"
model_name="ancestry pdf model"
tags_ids='9085d0d2-3333-1111-2222-4114602c2aa6,12345672-1111-2222-3333-456789012345'
pdf_metadata="{\"patient_name\": \"Patient Name\"}"

octo submit-order --file_id="${source_file_id}" --model="${model_name}" --tags_ids="${tags_ids}" --pdf_metadata="${pdf_metadata}"

Response

{
  "id": "1234567d-1111-2222-3333-12345abcd123",
  "amount_of_samples": 1,
  "model": "ancestry pdf model",
  "org_name": "your org name",
  "src_file_id": "b91dc168-5720-4f04-911f-a1c5aa14606d",
  "src_file_name": "filename.txt.zip",
  "src_file_short_path": "web_upload/2023-09-25/filename.txt.zip",
  "status": "Registered",
  "started_at": "2023-09-25T08:38:46.649136Z",
  "submitted_by": "your@email",
  "tags": [],
  "type": "GNT",
  "pdf_metadata": "{\"patient_name\": \"Patient Name\"}"
}

Submit execution order with ancestry report model.
All available models for your organization can be get in about me

Model API with ancestry PDF report generation

Possible results Description
SUMMARY_CHROMS Summary set of chromosomes, tsv file
SUMMARY_SUPERSET Summary superset of labels, tsv file
DETAILED_CHROMS Detailed set of labels by chromosome
DETAILED_SUPERSET Detailed superset of labels by chromosome, zip archive
EXEC_ERRORS Execution errors, contains errors about data processing
PDF_REPORT All generated PDF reports in zip archive

Payload fields:

pdf_metadata acceptable format type requirement
patient_name 'string' required
Payload example:
{
'source_file_id': source_file_id,
'model_name': 'ancestry pdf model',
'tags_ids': ['9085d0d2-3333-1111-2222-4114602c2aa6'],
'pdf_metadata': {'patient_name': 'Patient Name'}
}

PRS PDF order

Use access_token from Authentication step.
Instruction to Configure wrapper and client

Submit execution order using source_file_id and model name.

url_api = 'https://api.dev.galatea.bio/api/v1'
url_orders = f'{url_api}/exec/orders'

payload = {
    'source_file_id': source_file_id,
    'model_name': 'prs clinical model',
    'tags_ids': ['9085d0d2-3333-1111-2222-4114602c2aa6'],
    'pdf_report_types': ['PRS_RUO_CARDIO', 'PRS_RUO_CANCER', 'PRS_CLINICAL_CARDIO', 'PRS_CLINICAL_CANCER'],
    'pdf_metadata': {
        'patient_name': 'Patient Name',
        'dob': '2000-01-30',
        'sex': 'Female',
        'patient_id': '111-222-333-444-abc',
        'accession': '123str',
        'sample_id': 'sample-id-123',
        'collected': '2025-07-01',
        'received': '2025-07-15',
        'specimen_type': 'specimen type',
        'provider_name': 'Provider Name',
        'referring_facility': '123-456-789',
        'address': '777888 street',
    },
}

headers = {
    'accept': 'application/json',
    'Authorization': auth_token
}

response = requests.post(url_orders, json=payload, headers=headers)

print(response.text)
source_file_id = '3fa85f64-5717-4562-b3fc-2c963f66afa6'
model_name = 'prs clinical model'
tags_ids = ['9085d0d2-3333-1111-2222-4114602c2aa6']
pdf_report_types = ["PRS_RUO_CARDIO", "PRS_RUO_CANCER", "PRS_CLINICAL_CARDIO", "PRS_CLINICAL_CANCER"]
pdf_metadata = {
    'patient_name': 'Patient Name',
    'dob': '2000-01-30',
    'sex': 'Female',
    'patient_id': '111-222-333-444-abc',
    'accession': '123str',
    'sample_id': 'sample-id-123',
    'collected': '2025-07-01',
    'received': '2025-07-15',
    'specimen_type': 'specimen type',
    'provider_name': 'Provider Name',
    'referring_facility': '123-456-789',
    'address': '777888 street',
}

order_obj = octopod_client.order_api.submit_order(
    file_id=source_file_id,
    model_name=model_name,
    tags_ids=tags_ids,
    pdf_report_types=pdf_report_types,
    pdf_metadata=pdf_metadata,
)
source_file_id="3fa85f64-5717-4562-b3fc-2c963f66afa6"
model_name="prs clinical model"
pdf_metadata = "{\"patient_name\":\"Patient Name\",\"dob\":\"2000-01-30\",\"sex\":\"Female\",\"patient_id\":\"111-222-333-444-abc\",\"accession\":\"123str\",\"sample_id\":\"sample-id-123\",\"collected\":\"2025-07-01\",\"received\":\"2025-07-15\",\"specimen_type\":\"specimen type\",\"provider_name\":\"Provider Name\",\"referring_facility\":\"123-456-789\",\"address\":\"777888 street\"}"

curl -X 'POST' \
  'https://api.dev.galatea.bio/api/v1/exec/orders' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json' \
  -d '{
  "source_file_id": "${source_file_id}",
  "model_name": "${model_name}",
  "tags_ids": ["9085d0d2-3333-1111-2222-4114602c2aa6"],
  "pdf_report_types": "${pdf_report_types}",
  "pdf_metadata": "${pdf_metadata}"
}'
source_file_id="3fa85f64-5717-4562-b3fc-2c963f66afa6"
model_name="prs clinical model"
tags_ids='9085d0d2-3333-1111-2222-4114602c2aa6,12345672-1111-2222-3333-456789012345'
pdf_report_types = "PRS_RUO_CARDIO,PRS_RUO_CANCER,PRS_CLINICAL_CARDIO,PRS_CLINICAL_CANCER"
pdf_metadata = "{\"patient_name\":\"Patient Name\",\"dob\":\"2000-01-30\",\"sex\":\"Female\",\"patient_id\":\"111-222-333-444-abc\",\"accession\":\"123str\",\"sample_id\":\"sample-id-123\",\"collected\":\"2025-07-01\",\"received\":\"2025-07-15\",\"specimen_type\":\"specimen type\",\"provider_name\":\"Provider Name\",\"referring_facility\":\"123-456-789\",\"address\":\"777888 street\"}"

octo submit-order --file_id="${source_file_id}" --model="${model_name}" --tags_ids="${tags_ids}" --pdf_report_types="${pdf_report_types}" --pdf_metadata="${pdf_metadata}"

Response

{
  "id": "1234567d-1111-2222-3333-12345abcd123",
  "amount_of_samples": 1,
  "model": "prs clinical model",
  "org_name": "your org name",
  "src_file_id": "b91dc168-5720-4f04-911f-a1c5aa14606d",
  "src_file_name": "filename.txt.zip",
  "src_file_short_path": "web_upload/2023-09-25/filename.txt.zip",
  "status": "Registered",
  "started_at": "2023-09-25T08:38:46.649136Z",
  "submitted_by": "your@email",
  "tags": [],
  "type": "GNT",
  "pdf_metadata": "{\"patient_name\":\"Patient Name\",\"dob\":\"2000-01-30\",\"sex\":\"Female\",\"patient_id\":\"111-222-333-444-abc\",\"accession\":\"123str\",\"sample_id\":\"sample-id-123\",\"collected\":\"2025-07-01\",\"received\":\"2025-07-15\",\"specimen_type\":\"specimen type\",\"provider_name\":\"Provider Name\",\"referring_facility\":\"123-456-789\",\"address\":\"777888 street\"}"
}

Submit execution order with PRS reports model.
All available models for your organization can be get in about me

Model API with PRS PDF report generation

Possible results Description
SUMMARY_SUPERSET Summary superset of labels, tsv file
DETAILED_SUPERSET Detailed superset of labels by chromosome, zip archive
EXEC_ERRORS Execution errors, contains errors about data processing
PDF_REPORT All generated PDF reports in zip archive
PRS_JSON_DATA PRS data in json files per report type, zip archive
PRS_IMAGES PRS diagrams in png for high risk items, zip archive

Payload fields:

Acceptable values for pdf_report_types Description
PRS_RUO_CARDIO Research usage cardiometabolic report
PRS_RUO_CANCER Research usage cancer report
PRS_CLINICAL_CARDIO Clinical usage cardiometabolic report
PRS_CLINICAL_CANCER Clinical usage cancer report

IMPORTANT: For cancer reports (PRS_RUO_CANCER, PRS_CLINICAL_CANCER) biological sex is required field with acceptable values Male or Female only and case insensitive.

pdf_metadata acceptable format type requirement
patient_name 'string' optional
dob 'string, date format(YYYY-MM-DD)' optional
sex 'string' optional for cardio, required for cancer
patient_id 'string' optional
accession 'string' optional
sample_id 'string' optional
collected 'string, date format(YYYY-MM-DD)' optional
received 'string, date format(YYYY-MM-DD)' optional
specimen_type 'string' optional
provider_name 'string' optional
referring_facility 'string' optional
address 'string' optional
Payload examples:
{
'source_file_id': source_file_id,
'model_name': 'prs clinical model',
'tags_ids': ['9085d0d2-3333-1111-2222-4114602c2aa6'],
'pdf_report_types': ['PRS_CLINICAL_CARDIO', 'PRS_CLINICAL_CANCER'],
'pdf_metadata': {
'patient_name': 'Patient Name',
'dob': '2000-01-30',
'sex': 'Female',
'patient_id': '111-222-333-444-abc',
'accession': '123str',
'sample_id': 'sample-id-123',
'collected': '2025-07-01',
'received': '2025-07-15',
'specimen_type': 'specimen type',
'provider_name': 'Provider Name',
'referring_facility': '123-456-789',
'address': '777888 street',
}
{
'source_file_id': source_file_id,
'model_name': 'prs clinical model',
'pdf_report_types': ['PRS_CLINICAL_CARDIO', 'PRS_CLINICAL_CANCER'],
'pdf_metadata': {
'sex': 'male'
}

Get order info and get results

Use access_token from Authentication step.
Instruction to Configure wrapper and client

import requests

order_id = 'fc79a3e0-2222-3333-4444-506897b4f808'
url_api = 'https://api.dev.galatea.bio/api/v1'
url_orders = f'{url_api}/exec/orders?filter={order_id}'

headers = {
    'accept': 'application/json',
    'Authorization': auth_token
}

response = requests.get(url_orders, headers=headers)

print(f'order status: {json.loads(response.text)['results'][0]['status']}')
print(f'order result types: {json.loads(response.text)['results'][0]['result_types']}')
order_id = 'fc79a3e0-2222-3333-4444-506897b4f808'

order_obj = octopod_client.order_api.find_order_by_id_or_file_id(order_id)
order_status = order_obj.get('status')
order_result_types = order_obj.get('result_types')
order_id='fc79a3e0-2222-3333-4444-506897b4f808'
curl -X 'GET' \
  "https://api.dev.galatea.bio/api/v1/exec/orders?filter=${order_id}" \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
order_id='fc79a3e0-2222-3333-4444-506897b4f808'

octo find-order --order_id_or_file_id="$order_id"

Response

{
  "count": 1,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "fc79a3e0-2222-3333-4444-506897b4f808",
      "status": "Completed",
      "src_file_id": "9085d0d2-3333-1111-2222-4114602c2aa6",
      "src_file_short_path": "web-upload/2025-02-20/012716/filename.gvcf.gz",
      "src_file_name": "filename.gvcf.gz",
      "started_at": "2025-07-04T17:53:57.871506Z",
      "amount_of_samples": 1,
      "execution_time": 109.817911,
      "submitted_by": "[email protected]",
      "model": "ancestry data model one",
      "type": "WGS",
      "org_name": "Organization name",
      "tags": [],
      "result_types": [
        {
          "type": "SUMMARY_SUPERSET",
          "label": "Summary superset"
        },
        {
          "type": "DETAILED_SUPERSET",
          "label": "Detailed superset by chromosome"
        },
        {
          "type": "SUMMARY_CHROMS",
          "label": "Summary chromosomes"
        },
        {
          "type": "DETAILED_CHROMS",
          "label": "Detailed labels by chromosome"
        }
      ],
      "can_request_pdf": false,
      "virtual": false
    }
  ]
}

Use one of result_types from the response to download it.

import requests
import shutil

order_id = 'fc79a3e0-2222-3333-4444-506897b4f808'
result_type = 'SUMMARY_CHROMS'
url_api = 'https://api.dev.galatea.bio/api/v1'
url = f'{url_api}/data/results/{order_id}/download?result_type={result_type}'

headers = {
    'accept': 'application/json',
    'Authorization': auth_token
}

response = requests.get(url, headers=headers, stream=True)
filename = response.headers['content-disposition'].split('; ')[1].split('=')[1].replace('"', '')

with open(filename, 'wb') as out_file:
    shutil.copyfileobj(response.raw, out_file)

print(response.status_code)
order_id = 'fc79a3e0-2222-3333-4444-506897b4f808'

result_type = 'SUMMARY_CHROMS'

result_file_content: BytesIO, result_file_name: Optional[str] = octopod_client.result_api.download_result_file(
  order_id=order_id,
  result_type=result_type,
)

with open(result_file_name, "wb") as f:
    f.write(result_file_content.getbuffer())
order_id='fc79a3e0-2222-3333-4444-506897b4f808'
result_type='SUMMARY_CHROMS'

curl -X 'GET' \
  "https://api.dev.galatea.bio/api/v1/data/results/{order_id}/download?result_type=${result_type}" \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -o result_filename.tsv
order_id='fc79a3e0-2222-3333-4444-506897b4f808'
result_type='SUMMARY_CHROMS'

octo download-result-file --order_id="${order_id}" --result_type="${result_type}"

Avalable results of an order are related to configuration of your organization.
Results of order can be downloaded when order has one of statuses:

  1. Get order info, all available results for downloading are in result_types section.
  2. Download result file using order_id and one of result types from the order.

If order has status Failed, errors can be downloaded with result_type='EXEC_ERRORS'.

Possible result types for downloading:

Results type Description
SUMMARY_CHROMS Summary set of chromosomes, tsv file
SUMMARY_SUPERSET Summary superset of labels, tsv file
DETAILED_CHROMS Detailed set of labels by chromosome
DETAILED_SUPERSET Detailed superset of labels by chromosome, zip archive
EXEC_ERRORS Execution errors, contains errors about data processing
PDF_REPORT All generated PDF reports in zip archive
PRS_JSON_DATA PRS data in json files per report type, zip archive
PRS_IMAGES PRS diagrams in png for high risk items, zip archive

If configured websocket notifications for orders,
once an order will reach final status will be sent notification about it.

Download PDF reports

Supported 2 types of download:
- downloading all results as ZIP archive
- downloading one of reports from order by pdf_report_id

Get ZIP with PDF reports

Use auth_token from Authentication step.
Instruction to Configure wrapper and client

import requests
import shutil

order_id = '1234567d-1111-2222-3333-12345abcd123'
result_type = 'PDF_REPORT'

url = f'https://api.dev.galatea.bio/api/v1/data/results/{order_id}/download?result_type={result_type}'
headers = {
    "accept": "application/json",
    "content-type": "application/json",
    "Authorization": "Bearer <<access_token>>"
}

response = requests.get(url, headers=headers, stream=True)
filename = response.headers['content-disposition'].split('; ')[1].split('=')[1].replace('"', '')

with open(filename, 'wb') as out_file:
    shutil.copyfileobj(response.raw, out_file)

print(response.status_code)
order_id = '1234567d-1111-2222-3333-12345abcd123'

result_type = 'PDF_REPORT'

result_file_content: BytesIO, result_file_name: Optional[str] = octopod_client.result_api.download_result_file(
  order_id=order_id,
  result_type=result_type,
)

with open(result_file_name, "wb") as f:
    f.write(result_file_content.getbuffer())
curl -X 'GET' \
  'https://api.dev.galatea.bio/api/v1data/results/1234567d-1111-2222-3333-12345abcd123/download?result_type=PDF_REPORT' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -o result_filename.tsv
order_id='1234567d-1111-2222-3333-12345abcd123'
result_type="PDF_REPORT"

octo download-result-file --order_id="${order_id}" --result_type="${result_type}"

When an order is completed, all pdf reports are stored into 1 zip archive.
result_type parameter for downloading zip archive: result_type=PDF_REPORT

Get single PDF report file

Use auth_token from Authentication step.
Instruction to Configure wrapper and client

Get list of PDF reports for order

import requests

order_id = '1234567d-1111-2222-3333-12345abcd123'
url_api = 'https://api.dev.galatea.bio/api/v1'
url_order_pdf = f'{url_api}/data/results/{order_id}/pdf_report?page_size=1000'

headers = {
    'accept': 'application/json',
    'Authorization': auth_token
}

response = requests.get(url_order_pdf, headers=headers)

print(response.text)
order_id = '1234567d-1111-2222-3333-12345abcd123'

octopod_client.result_api.list_pdf_reports(order_id=order_id)
order_id='1234567d-1111-2222-3333-12345abcd123'
curl -X 'GET' \
  "https://api.dev.galatea.bio/api/v1/data/results/{$order_id}/pdf_report?page_size=1000" \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -H 'Content-Type: application/json'
order_id='1234567d-1111-2222-3333-12345abcd123'

octo list-result-pdf-reports --order_id="${order_id}"

Response:

{
  "count": 2,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "91e29ebd-e0b2-46bf-b060-8b1b9be42612",
      "status": "COMPLETED",
      "sample_id": "sandbox-0-fb82245c-3708",
      "order_id": "1234567d-1111-2222-3333-12345abcd123",
      "result_id": "b27d241d-1022-4104-b99a-6f57fdfdf09c",
      "org_name": "Organization Name",
      "report_type": "PRS_RUO_CANCER",
      "request_type": "ORDER",
      "request_version": 1,
      "report_version": "",
      "pdf_file_name": "91e29ebd-e0b2-46bf-b060-8b1b9be42612_sandbox-0-fb82245c-3708_prs-ruo-cancer.pdf",
      "file_size_bytes": 1009409,
      "check_sum": "bf32dd3fb73694892f0c775fa95ad63a",
      "started_at": "2025-07-04T17:56:32.933564Z",
      "completed_at": "2025-07-04T17:56:46.138287Z"
    },
    {
      "id": "5639d15b-0dc8-4c61-ada0-ec39b1ad5417",
      "status": "COMPLETED",
      "sample_id": "sandbox-0-fb82245c-3708",
      "order_id": "1234567d-1111-2222-3333-12345abcd123",
      "result_id": "b27d241d-1022-4104-b99a-6f57fdfdf09c",
      "org_name": "Organization Name",
      "report_type": "PRS_RUO_CARDIO",
      "request_type": "ORDER",
      "request_version": 1,
      "report_version": "",
      "pdf_file_name": "5639d15b-0dc8-4c61-ada0-ec39b1ad5417_sandbox-0-fb82245c-3708_prs-ruo-cardio.pdf",
      "file_size_bytes": 3193962,
      "check_sum": "421373d67eaa44a249ee56bebd3529ed",
      "started_at": "2025-07-04T17:56:06.027039Z",
      "completed_at": "2025-07-04T17:56:28.092727Z"
    }
  ]
}

Download one completed PDF report file.

import requests
import shutil

order_id = '1234567d-1111-2222-3333-12345abcd123'
pdf_request_id = '91e29ebd-e0b2-46bf-b060-8b1b9be42612'
url_api = 'https://api.dev.galatea.bio/api/v1'

url = f'{url_api}/data/results/{order_id}/download?result_type=PDF_REPORT&pdf_request_id={pdf_request_id}'

headers = {
    'accept': 'application/json',
    'Authorization': auth_token
}

response = requests.get(url, headers=headers, stream=True)
filename = response.headers['content-disposition'].split('; ')[1].split('=')[1].replace('"', '')

with open(filename, 'wb') as out_file:
    shutil.copyfileobj(response.raw, out_file)

print(response.status_code)
order_id = '1234567d-1111-2222-3333-12345abcd123'
pdf_request_id = '91e29ebd-e0b2-46bf-b060-8b1b9be42612'

result_type = 'PDF_REPORT'

result_file_content: BytesIO, result_file_name: str = octopod_client.result_api.download_result_file(
  order_id=order_id,
  result_type=result_type,
  pdf_request_id=pdf_request_id,
)

with open(result_file_name, "wb") as f:
    f.write(result_file_content.getbuffer())
order_id='1234567d-1111-2222-3333-12345abcd123'
pdf_request_id='91e29ebd-e0b2-46bf-b060-8b1b9be42612'

curl -X 'GET' \
  "https://api.dev.galatea.bio/api/v1/data/results/{$order_id}/download?result_type=PDF_REPORT&pdf_request_id={$pdf_request_id}" \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer <<access_token>>' \
  -o result_filename.tsv
order_id='1234567d-1111-2222-3333-12345abcd123'
pdf_request_id='91e29ebd-e0b2-46bf-b060-8b1b9be42612'
result_type="PDF_REPORT"

octo download-result-file --order_id="${order_id}" --result_type="${result_type} --pdf_request_id="${pdf_request_id}"

To download single completed report:
1. Get list of pdf reports in order results.
2. Download PDF report using pdf_request_id.

Handling webhooks deliveries

Prepare FastAPI webserver

import base64
import hashlib
import hmac
import json

import uvicorn
from fastapi import FastAPI, Request, Depends, Response

app = FastAPI()


async def get_body(request: Request):
    return await request.body()


@app.post("/webhook_handler/")
async def webhook_handler(request: Request, payload: bytes = Depends(get_body)):
    signature_header = request.headers.get('X-Octopod-Signature')
    if signature_header is None:
        print('Incorrect webhook: signature header is missed.')
        return Response(status_code=422)

    payload_str = payload.decode("utf-8")
    sender_host = 'api.dev.galatea.bio'
    signature_data = sender_host + payload_str
    webhooks_secret = 'webhooks-secret'

    signature = base64.b64encode(
        hmac.new(
            key=bytes(webhooks_secret, 'utf-8'),
            msg=bytes(signature_data, 'utf-8'),
            digestmod=hashlib.sha256
        ).digest()
    ).decode()

    if signature == signature_header:
        print('signature is valid, processing webhook data')
        payload_dict = json.loads(payload_str)
        if payload_dict is None or payload_dict == {}:
            print(f'Incorrect webhook: {payload_str}')
            return Response(content='Incorrect webhook payload.', status_code=422)

        # webhook for order
        if 'order_id' in payload_dict and 'new_status' in payload_dict and 'source_file_id' in payload_dict and 'source_file_name' in payload_dict:
            order_id = payload_dict.get('order_id', None)
            new_status = payload_dict.get('new_status', None)
            source_file_id = payload_dict.get('source_file_id', None)
            source_file_name = payload_dict.get('source_file_name', None)
            print(f'Received webhook for order:\n'
                  f'order_id: {order_id}\n'
                  f'new_status: {new_status}\n'
                  f'source_file_id: {source_file_id}\n'
                  f'source_file_name: {source_file_name}')
            return Response(status_code=200)

        # webhook for source file
        if 'new_status' in payload_dict and 'source_file_id' in payload_dict and 'source_file_name' in payload_dict:
            new_status = payload_dict.get('new_status', None)
            source_file_id = payload_dict.get('source_file_id', None)
            source_file_name = payload_dict.get('source_file_name', None)
            print(f'Received webhook for source file:\n'
                  f'new_status: {new_status}\n'
                  f'source_file_id: {source_file_id}\n'
                  f'source_file_name: {source_file_name}')
            return Response(status_code=200)

    return Response(status_code=422)
# use python code example
# use python code example
# use python code example

Start FastAPI webserver

fastapi dev main.py --host 0.0.0.0 --port 8888
# use python code example
# use python code example
# use python code example

Source file validation JSON response

{
  "source_file_id": "7e53320c-c631-45ec-bad6-c88bb9d30960",
  "new_status": "VALID",
  "source_file_name": "d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz"
}

Order completion JSON payload

{
  "order_id": "c1ea8279-25c2-4a36-9ea6-41e54239f17b",
  "new_status": "COMPLETED",
  "source_file_id": "7e53320c-c631-45ec-bad6-c88bb9d30960",
  "source_file_name": "d101979c-348c-44cd-8279-e9207b5a67a7.vcf.gz"
}

This example is based on FastAPI.
Assuming webserver is available on public address and routes to FastAPI server.

Organization Admins can configure webhooks for source files and orders.

webhooks-secret is available on Intergations -> Webhooks tab.

sender_host is api.dev.galatea.bio
Note: for sandbox use host api.sandbox.galatea.bio

Source file validation completed: once validation for uploaded file completed, notification will be sent with results.
Order moved to completed stay: once order passed to one of final stay - Completed or Failed, notification will be sent.

Example:

Webhook type Address
Source file validation completed https://webhooks.example.com/webhook_handler/
Order moved to completed stay https://webhooks.example.com/webhook_handler/

On Test webhook will be send messages with fake data:

Webhook type Message
Source file validation completed {
"new_status": "VALID",
"source_file_id": "11111111-1111-1111-1111-111111111111",
"source_file_name": "test_message_source_file_validated.vcf.gz"
}
Order moved to completed stay {
"order_id": "22222222-2222-2222-2222-222222222222",
"new_status": "COMPLETED",
"source_file_id": "33333333-3333-3333-3333-333333333333",
"source_file_name": "test_message_order_completed.vcf.gz"
}

Errors

The GalateaBio Ancestry API uses the following error codes:

Error Code Meaning
400 Bad Request -- Your request is invalid.
401 Unauthorized -- Your API key is wrong.
403 Forbidden -- The information requested is hidden for administrators only.
404 Not Found -- The specified information could not be found.
405 Method Not Allowed -- You tried to access an information with an invalid method.
406 Not Acceptable -- You requested a format that isn't json.
422 Unprocessable Entity -- Your request contains incorrect data.
500 Internal Server Error -- We had a problem with our server. Try again later.
503 Service Unavailable -- We're temporarily offline for maintenance. Please try again later.