Repository: refgenie/refget (language: python)

Issue:
Adds seqcolapi endpoint service to refget package



Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 55ae73f..168622f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,4 +79,4 @@ refget.egg-info/
 *ipynb_checkpoints*
 *.egg-info*
 
-
+coverage.xml
diff --git a/README.md b/README.md
index 7d9660d..a85fb4a 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,31 @@
 # Refget
 
-[![Build Status](https://travis-ci.com/refgenie/refget.svg?branch=master)](https://travis-ci.com/refgenie/refget)
+![Run pytests](https://github.com/pepkit/looper/workflows/Run%20pytests/badge.svg)
 
 The refget package provides a Python interface to both remote and local use of the refget protocol.
 
 This package provides clients and functions for both refget sequences and refget sequence collections (seqcol).
 
 Documentation is hosted at [refgenie.org/refget](https://refgenie.org/refget/).
+
+## Testing
+
+### Local unit tests of refget package
+
+- `pytest` to test `refget` package, local unit tests
+
+### Compliance testing 
+
+Under `/test_api` are compliance tests for a service implementing the sequence collections API. This will test your collection and comparison endpoints to make sure the comparison function is working. 
+
+- `pytest test_api` to tests API compliance
+- `pytest test_api --api_root http://127.0.0.1:8100` to customize the API root URL to test
+
+1. Load the fasta files from the `test_fasta` folder into your API database.
+2. Run `pytest test_api --api_root <API_URL>`, pointing to your URL to test
+
+For example, this will test my remote server instance:
+
+```
+pytest test_api --api_root https://seqcolapi.databio.org
+```
diff --git a/README_seqcolapi.md b/README_seqcolapi.md
new file mode 100644
index 0000000..8e8f980
--- /dev/null
+++ b/README_seqcolapi.md
@@ -0,0 +1,85 @@
+# seqcolapi
+
+This repository contains:
+
+1. Sequence collections API software (the `seqcolapi` package). This package is based on the `refget` package. It simply provides an wrapper to implement the Sequence Collections API.
+2. Configuration and GitHub Actions for demo server instance ([servers subfolder](/servers)).
+
+## Instructions
+
+### Run locally for development
+
+First, configure env vars:
+- To run a local server with a **local database**:`source servers/localhost/dev_local.env`
+- To run a local server with **the production database**:`source servers/seqcolapi.databio.org/production.env`
+
+Then, run service:
+
+```
+uvicorn seqcolapi.main:app --reload --port 8100
+```
+
+### Running with docker
+
+To build the docker file, from the root of this repository:
+
+First you build the general-purpose image
+
+```
+docker build -f deployment/dockerhub/Dockerfile -t databio/seqcolapi seqcolapi
+```
+
+Next you build the wrapped image (this just wraps the config into the app):
+
+```
+docker build -f deployment/seqcolapi.databio.org/Dockerfile -t seqcolapi.databio.org deployment/seqcolapi.databio.org
+```
+
+To run in a container:
+```
+source deployment/seqcolapi.databio.org/production.env
+docker run --rm -p 8000:80 --name seqcolapi \
+  --env "POSTGRES_PASSWORD" \
+  --env "POSTGRES_HOST" \
+  seqcolapi.databio.org
+```
+
+### Alternative: Mount the config
+Instead of building a bundle with the config, you could just mount it into the base image:
+```
+docker run --rm -p 8000:8000 --name sccon \
+  --env "POSTGRES_PASSWORD" \
+  --volume $CODE/seqcolapi.databio.org/config/seqcolapi.yaml:/config.yaml \
+  seqcolapi 
+```
+
+### Deploying container to dockerhub
+
+Use github action in this repo which deploys on release, or through manual dispatch.
+
+## To load new data into seqcolapi.databio.org
+
+See instructions in `seqcolapi` repo.
+```
+cd analysis
+source ../servers/localhost/dev_local.env
+ipython3
+```
+
+Now run `load_fasta.py`
+
+## Deploy to AWS ECS
+
+- Test locally first, using 1. native test; 2. local docker test.
+
+### Deploying
+
+To upgrade the software:
+
+Use config file located in `/servers/seqcolapi.databio.org`. This will use the image in docker.io://databio/seqcolapi, github repo: [refgenie/seqcolapi](https://github.com/refgenie/seqcolapi) as base, bundle it with the above config, and deploy to the shefflab ECS.
+
+1. Ensure the [refget](https://github.com/refgenie/refget/) package master branch is as you want it.
+2. Deploy the updated [secqolapi](https://github.com/refgenie/seqcolapi/) app to dockerhub (using manual dispatch, or deploy on github release).
+3. Finally, deploy the instance with manual dispatch using the included GitHub action.
+
+
diff --git a/demo_fasta/demo4.fa b/demo_fasta/demo4.fa
index ade4e7a..fb715c2 100644
--- a/demo_fasta/demo4.fa
+++ b/demo_fasta/demo4.fa
@@ -1,2 +1,6 @@
+>chr2
+ACGT
+>chr1
+TCGA
 >chrX
 TTCCGGAA
diff --git a/demo_fasta/demo4.fa.fai b/demo_fasta/demo4.fa.fai
index 0d84e86..3086e4d 100644
--- a/demo_fasta/demo4.fa.fai
+++ b/demo_fasta/demo4.fa.fai
@@ -1,1 +1,3 @@
-chrX	8	6	8	9
+chr2	4	6	4	5
+chr1	4	17	4	5
+chrX	8	28	8	9
diff --git a/deployment/dockerhub/Dockerfile b/deployment/dockerhub/Dockerfile
new file mode 100644
index 0000000..144db8a
--- /dev/null
+++ b/deployment/dockerhub/Dockerfile
@@ -0,0 +1,11 @@
+FROM tiangolo/uvicorn-gunicorn:python3.11-slim
+LABEL authors="Nathan Sheffield"
+RUN pip install https://github.com/databio/yacman/archive/dev.zip
+RUN pip install https://github.com/refgenie/refget/archive/dev.zip
+
+COPY requirements/requirements-seqcolapi.txt requirements/requirements-seqcolapi.txt
+RUN pip install -r requirements/requirements-seqcolapi.txt --no-cache-dir
+
+COPY . /app/seqcolapi
+
+CMD ["uvicorn", "seqcolapi.main:app", "--host", "0.0.0.0", "--port", "80"]
diff --git a/deployment/localhost/dev_local.env b/deployment/localhost/dev_local.env
new file mode 100644
index 0000000..1d969c7
--- /dev/null
+++ b/deployment/localhost/dev_local.env
@@ -0,0 +1,9 @@
+export POSTGRES_HOST=`pass databio/seqcol/postgres_host`
+export POSTGRES_DB=`pass databio/seqcol/postgres_db`
+export POSTGRES_USER=`pass databio/seqcol/postgres_user`
+export POSTGRES_PASSWORD=`pass databio/seqcol/postgres_password`
+export POSTGRES_TABLE="seqcol"
+
+export SEQCOLAPI_PORT="8100"
+export SERVER_ENV="dev"
+export SEQCOLAPI_CONFIG="servers/localhost/seqcolapi.yaml"
diff --git a/deployment/localhost/seqcolapi.yaml b/deployment/localhost/seqcolapi.yaml
new file mode 100644
index 0000000..9ad1a99
--- /dev/null
+++ b/deployment/localhost/seqcolapi.yaml
@@ -0,0 +1,13 @@
+refget_provider_apis: https://www.ebi.ac.uk/ena/cram/sequence/
+schemas:
+- https://schema.databio.org/refget/SeqColArraySetInherent.yaml
+database:
+  host: $POSTGRES_HOST
+  user: $POSTGRES_USER
+  password: $POSTGRES_PASSWORD
+  port: 5432
+  name: $POSTGRES_DB
+  table: seqcol
+server:
+  host: 0.0.0.0
+  port: 80
diff --git a/deployment/seqcolapi.databio.org/Dockerfile b/deployment/seqcolapi.databio.org/Dockerfile
new file mode 100644
index 0000000..7fcc959
--- /dev/null
+++ b/deployment/seqcolapi.databio.org/Dockerfile
@@ -0,0 +1,3 @@
+FROM databio/seqcolapi
+COPY seqcolapi.yaml /seqcolapi_config.yaml
+ENV SEQCOLAPI_CONFIG /seqcolapi_config.yaml
diff --git a/deployment/seqcolapi.databio.org/primary_task_def.json b/deployment/seqcolapi.databio.org/primary_task_def.json
new file mode 100644
index 0000000..1f88f81
--- /dev/null
+++ b/deployment/seqcolapi.databio.org/primary_task_def.json
@@ -0,0 +1,105 @@
+{
+  "ipcMode": null,
+  "executionRoleArn": "arn:aws:iam::235728444054:role/ecsTaskExecutionRole",
+  "containerDefinitions": [
+    {
+      "dnsSearchDomains": null,
+      "environmentFiles": null,
+      "logConfiguration": null,
+      "entryPoint": null,
+      "portMappings": [
+        {
+          "hostPort": 8105,
+          "protocol": "tcp",
+          "containerPort": 80
+        }
+      ],
+      "command": null,
+      "linuxParameters": null,
+      "cpu": 0,
+      "environment": [],
+      "resourceRequirements": null,
+      "ulimits": null,
+      "dnsServers": null,
+      "mountPoints": [],
+      "workingDirectory": null,
+      "secrets": [
+        {
+          "valueFrom": "SEQCOLAPI_POSTGRES_PASSWORD",
+          "name": "POSTGRES_PASSWORD"
+        },
+        {
+          "valueFrom": "BEDBASE_POSTGRES_HOST",
+          "name": "POSTGRES_HOST"
+        }
+      ],
+      "dockerSecurityOptions": null,
+      "memory": 2048,
+      "memoryReservation": 512,
+      "volumesFrom": [],
+      "stopTimeout": null,
+      "image": "235728444054.dkr.ecr.us-east-1.amazonaws.com/my-ecr-repo:170afd5cf39d9799e926e1d0ebf40b9051fb731f",
+      "startTimeout": null,
+      "firelensConfiguration": null,
+      "dependsOn": null,
+      "disableNetworking": null,
+      "interactive": null,
+      "healthCheck": null,
+      "essential": true,
+      "links": null,
+      "hostname": null,
+      "extraHosts": null,
+      "pseudoTerminal": null,
+      "user": null,
+      "readonlyRootFilesystem": null,
+      "dockerLabels": null,
+      "systemControls": null,
+      "privileged": null,
+      "name": "seqcolapi"
+    }
+  ],
+  "placementConstraints": [],
+  "memory": null,
+  "taskRoleArn": "ecsTaskExecutionRole",
+  "compatibilities": [
+    "EC2"
+  ],
+  "family": "seqcolapi-task",
+  "requiresAttributes": [
+    {
+      "targetId": null,
+      "targetType": null,
+      "value": null,
+      "name": "com.amazonaws.ecs.capability.ecr-auth"
+    },
+    {
+      "targetId": null,
+      "targetType": null,
+      "value": null,
+      "name": "com.amazonaws.ecs.capability.docker-remote-api.1.21"
+    },
+    {
+      "targetId": null,
+      "targetType": null,
+      "value": null,
+      "name": "com.amazonaws.ecs.capability.task-iam-role"
+    },
+    {
+      "targetId": null,
+      "targetType": null,
+      "value": null,
+      "name": "ecs.capability.execution-role-ecr-pull"
+    }
+  ],
+  "pidMode": null,
+  "requiresCompatibilities": [
+    "EC2"
+  ],
+  "networkMode": "bridge",
+  "cpu": "128",
+  "revision": 1,
+  "status": "ACTIVE",
+  "inferenceAccelerators": null,
+  "proxyConfiguration": null,
+  "volumes": []
+}
diff --git a/deployment/seqcolapi.databio.org/production.env b/deployment/seqcolapi.databio.org/production.env
new file mode 100644
index 0000000..5ddb740
--- /dev/null
+++ b/deployment/seqcolapi.databio.org/production.env
@@ -0,0 +1,9 @@
+export POSTGRES_HOST=`pass databio/seqcol/postgres_host`
+export POSTGRES_DB=`pass databio/seqcol/postgres_db`
+export POSTGRES_USER=`pass databio/seqcol/postgres_user`
+export POSTGRES_PASSWORD=`pass databio/seqcol/postgres_password`
+export POSTGRES_TABLE="seqcol"
+
+export SEQCOLAPI_PORT="5432"
+export SERVER_ENV="production"
+export SEQCOLAPI_CONFIG="deployment/seqcolapi.databio.org/seqcolapi.yaml"
diff --git a/deployment/seqcolapi.databio.org/seqcolapi.yaml b/deployment/seqcolapi.databio.org/seqcolapi.yaml
new file mode 100644
index 0000000..a9464ed
--- /dev/null
+++ b/deployment/seqcolapi.databio.org/seqcolapi.yaml
@@ -0,0 +1,13 @@
+refget_provider_apis: https://www.ebi.ac.uk/ena/cram/sequence/
+schemas:
+- https://schema.databio.org/refget/SeqColArraySetInherent.yaml
+database:
+  host: $POSTGRES_HOST
+  user: seqcol_admin
+  password: $POSTGRES_PASSWORD
+  port: 5432
+  name: seqcol
+  table: seqcol
+server:
+  host: 0.0.0.0
+  port: 80
diff --git a/refget/__init__.py b/refget/__init__.py
index 897c9fa..eead32f 100644
--- a/refget/__init__.py
+++ b/refget/__init__.py
@@ -10,3 +10,10 @@
 from .seqcol import *
 from .utilities import *
 from .seqcol_client import *
+
+try:
+    # Requires optional dependencies, so we catch the ImportError
+    from .seqcol_router import seqcol_router
+except ImportError:
+    seqcol_router = None
+    pass
diff --git a/refget/_version.py b/refget/_version.py
index d3ec452..493f741 100644
--- a/refget/_version.py
+++ b/refget/_version.py
@@ -1,1 +1,1 @@
-__version__ = "0.2.0"
+__version__ = "0.3.0"
diff --git a/refget/examples.py b/refget/examples.py
new file mode 100644
index 0000000..2704252
--- /dev/null
+++ b/refget/examples.py
@@ -0,0 +1,143 @@
+# Models
+# Used for documentation examples in OpenAPI
+
+from fastapi import Path, Body
+
+example_digest = Path(
+    ...,
+    description="Sequence collection digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="a6748aa0f6a1e165f871dbed5e54ba62",
+)
+
+example_digest_2 = Path(
+    ...,
+    description="Sequence collection digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="2786eb8a921aa97018c214f64b9960a0",
+)
+
+example_digest_hg38 = Path(
+    ...,
+    description="Sequence collection digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="514c871928a74885ce981faa61ccbb1a",
+)
+
+example_digest_hg38_primary = Path(
+    ...,
+    description="Sequence collection digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="c345e091cce0b1df78bfc124b03fba1c",
+)
+
+example_sequence = Path(
+    ...,
+    description="Refget sequence digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="76f9f3315fa4b831e93c36cd88196480",
+)
+
+example_hg38_sc = Body(
+    {
+        "lengths": [
+            "248956422",
+            "242193529",
+            "198295559",
+            "190214555",
+            "181538259",
+            "170805979",
+            "159345973",
+            "145138636",
+            "138394717",
+            "133797422",
+            "135086622",
+            "133275309",
+            "114364328",
+            "107043718",
+            "101991189",
+            "90338345",
+            "83257441",
+            "80373285",
+            "58617616",
+            "64444167",
+            "46709983",
+            "50818468",
+            "16569",
+            "156040895",
+            "57227415",
+        ],
+        "names": [
+            "chr1",
+            "chr2",
+            "chr3",
+            "chr4",
+            "chr5",
+            "chr6",
+            "chr7",
+            "chr8",
+            "chr9",
+            "chr10",
+            "chr11",
+            "chr12",
+            "chr13",
+            "chr14",
+            "chr15",
+            "chr16",
+            "chr17",
+            "chr18",
+            "chr19",
+            "chr20",
+            "chr21",
+            "chr22",
+            "chrM",
+            "chrX",
+            "chrY",
+        ],
+        "sequences": [
+            "a004bc1b0bf05fc668cab6bbfd93d3eb",
+            "0ccf3a67666ac53f99fcad19768f2dde",
+            "bda7b228789169ae811dd8d676d517ca",
+            "88a6091e2d9a609f4ea7eaef937cd4c2",
+            "0f1725f15e8046a6a04e32de629b1e10",
+            "08c3702d62a2c476a081d3ccd15ea30c",
+            "cac9e313d08cdf40c9eeafe62b17879a",
+            "9a2ebb88dc34c2af023d50219248c815",
+            "41bbec590d36e711864dc6f030f0264b",
+            "6b420cbb22daea77d7cc930c0a00f812",
+            "0d4e0be5c4e5bc0f12912894f21a5dd8",
+            "e1507ba70028a65b3f5a81b594e6f0fe",
+            "7110500758388b169fe631b212b7e56c",
+            "f37e77fdbacb1a0f1be5e2bf25df343d",
+            "3f14ce1984dada290682eb1f564934ee",
+            "88169bd58f0c5f9fd083030d1357d908",
+            "0bbc162a7d963574b5989adab5651ac5",
+            "388e8c7cd11a23eebf84a02d5e442bb7",
+            "1c927775585df1cb09ec7c7dd1b32a6a",
+            "c37960f60eff5e2cfbde87e53d262efa",
+            "f0324d60ccf85288a26a47a7ca25a54a",
+            "f7479d5a2a3169e2e44d97d7f2a13db1",
+            "6ab1f3c8f4941e148463c40408c89e43",
+            "6bdaf93397b486a58fd60b55aa2e21ca",
+            "9bd609da53b41a50a724f2a0131ee9c1",
+        ],
+    }
+)
+
+reclimit_ex = Path(
+    ...,
+    description="Recursion limit, the number of times to recurse to populate digests in the structure",
+    gt=-1,
+    lt=2,
+    examples=0,
+)
diff --git a/refget/seqcol.py b/refget/seqcol.py
index ba6ff56..5b81f72 100644
--- a/refget/seqcol.py
+++ b/refget/seqcol.py
@@ -1,6 +1,5 @@
 import henge
 import logging
-import yacman
 
 from itertools import compress
 
@@ -12,26 +11,6 @@
 henge.ITEM_TYPE = "_item_type"
 
 
-class SeqColConf(yacman.YAMLConfigManager):
-    """
-    Simple configuration manager object for SeqColHenge.
-    """
-
-    def __init__(
-        self,
-        entries={},
-        filepath=None,
-        yamldata=None,
-        writable=False,
-        wait_max=60,
-        skip_read_lock=False,
-    ):
-        filepath = yacman.select_config(
-            config_filepath=filepath, config_env_vars=["SEQCOLAPI_CONFIG"], config_name="seqcol"
-        )
-        super(SeqColConf, self).__init__(entries, filepath, yamldata, writable)
-
-
 class SeqColHenge(henge.Henge):
     """
     Extension of henge that accommodates collections of sequences.
diff --git a/refget/seqcol_router.py b/refget/seqcol_router.py
new file mode 100644
index 0000000..2087279
--- /dev/null
+++ b/refget/seqcol_router.py
@@ -0,0 +1,151 @@
+"""
+This module contains the FastAPI router for the sequence collection API.
+It is designed to be attached to a FastAPI app instance, and provides
+endpoints for retrieving and comparing sequence collections.
+
+To use, first import it, then attach it to the app,
+then attach the schenge to the app state, like this:
+
+from refget import seqcol_router
+app.include_router(seqcol_router, prefix="/seqcol")
+app.state.schenge = schenge
+"""
+
+import henge
+import logging
+
+from fastapi import APIRouter, Response, HTTPException, Request, Depends
+from fastapi.responses import JSONResponse
+from typing import Union
+
+from .examples import *
+
+_LOGGER = logging.getLogger(__name__)
+
+seqcol_router = APIRouter()
+
+
+async def get_schenge(request: Request):
+    """Dependency to get the schenge from the app state"""
+    return request.app.state.schenge
+
+
+@seqcol_router.get("/test")
+async def test(schenge=Depends(get_schenge)):
+    return str(schenge)
+
+
+@seqcol_router.get(
+    "/sequence/{digest}",
+    summary="Retrieve raw sequence via refget protocol",
+    tags=["Refget endpoints"],
+)
+async def refget(request: Request, digest: str = example_sequence):
+    schenge = request.app.state.schenge
+    return Response(content=schenge.refget(digest))
+
+
+@seqcol_router.get(
+    "/collection/{digest}",
+    summary="Retrieve a sequence collection",
+    tags=["Retrieving sequence collections"],
+)
+async def collection(
+    schenge=Depends(get_schenge),
+    digest: str = example_digest,
+    level: Union[int, None] = None,
+    collated: bool = True,
+):
+    print("Retrieving collection")
+    print(str(schenge))
+    if level == None:
+        level = 2
+    if level > 2:
+        raise HTTPException(
+            status_code=400,
+            detail="Error: recursion > 1 disabled. Use the /refget server to retrieve sequences.",
+        )
+    try:
+        csc = schenge.retrieve(digest, reclimit=level - 1)
+    except henge.NotFoundException as e:
+        _LOGGER.debug(e)
+        raise HTTPException(
+            status_code=404,
+            detail="Error: collection not found. Check the digest and try again.",
+        )
+    try:
+        if not collated:
+            if len(csc["lengths"]) > 10000:
+                raise HTTPException(
+                    status_code=413,
+                    detail="This server won't decollate collections with > 10000 sequences",
+                )
+            else:
+                return JSONResponse(content=format_itemwise(csc))
+        else:
+            return JSONResponse(content=csc)
+    except:
+        raise HTTPException(
+            status_code=404,
+            detail="Error: collection not found. Check the digest and try again.",
+        )
+
+
+@seqcol_router.get(
+    "/comparison/{digest1}/{digest2}",
+    summary="Compare two sequence collections hosted on the server",
+    tags=["Comparing sequence collections"],
+)
+async def compare_2_digests(
+    schenge=Depends(get_schenge),
+    digest1: str = example_digest_hg38,
+    digest2: str = example_digest_hg38_primary,
+):
+    _LOGGER.info("Compare called")
+    result = {}
+    result["digests"] = {"a": digest1, "b": digest2}
+    try:
+        result.update(schenge.compare_digests(digest1, digest2))
+    except henge.NotFoundException as e:
+        _LOGGER.debug(e)
+        raise HTTPException(
+            status_code=404,
+            detail="Error: collection not found. Check the digest and try again.",
+        )
+    return JSONResponse(result)
+
+
+@seqcol_router.post(
+    "/comparison/{digest1}",
+    summary="Compare a local sequence collection to one on the server",
+    tags=["Comparing sequence collections"],
+)
+async def compare_1_digest(
+    schenge=Depends(get_schenge), digest1: str = example_digest_hg38, B: dict = example_hg38_sc
+):
+    _LOGGER.info(f"digest1: {digest1}")
+    _LOGGER.info(f"B: {B}")
+    A = schenge.retrieve(digest1, reclimit=1)
+    return JSONResponse(schenge.compat_all(A, B))
+
+
+@seqcol_router.get(
+    "/list-by-offset",
+    summary="List sequence collections on the server",
+    tags=["Listing sequence collections"],
+)
+async def list_collections_by_offset(
+    schenge=Depends(get_schenge), limit: int = 100, offset: int = 0
+):
+    return JSONResponse(schenge.list_by_offset(limit=limit, offset=offset))
+
+
+@seqcol_router.get(
+    "/list",
+    summary="List sequence collections on the server",
+    tags=["Listing sequence collections"],
+)
+async def list_collections_by_token(
+    schenge=Depends(get_schenge), page_size: int = 100, cursor: str = None
+):
+    return JSONResponse(schenge.list(page_size=page_size, cursor=cursor))
diff --git a/refget/utilities.py b/refget/utilities.py
index 573e3ef..c21e560 100644
--- a/refget/utilities.py
+++ b/refget/utilities.py
@@ -7,7 +7,7 @@
 import pyfaidx
 
 from jsonschema import Draft7Validator
-from typing import Optional, Callable
+from typing import Optional, Callable, Union
 from yacman import load_yaml
 
 from .const import SeqCol
@@ -23,18 +23,27 @@ def trunc512_digest(seq, offset=24) -> str:
     return hex_digest.decode()
 
 
-def sha512t24u_digest(seq: str, offset: int = 24) -> str:
+def sha512t24u_digest(seq: Union[str, bytes], offset: int = 24) -> str:
     """GA4GH digest function"""
-    digest = hashlib.sha512(seq.encode()).digest()
+    if isinstance(seq, str):
+        seq = seq.encode("utf-8")
+    digest = hashlib.sha512(seq).digest()
     tdigest_b64us = base64.urlsafe_b64encode(digest[:offset])
     return tdigest_b64us.decode("ascii")
 
 
-def canonical_str(item: dict) -> str:
+def sha512t24u_digest_bytes(seq: bytes, offset: int = 24) -> str:
+    """GA4GH digest function"""
+    digest = hashlib.sha512(seq).digest()
+    tdigest_b64us = base64.urlsafe_b64encode(digest[:offset])
+    return tdigest_b64us.decode("ascii")
+
+
+def canonical_str(item: dict) -> bytes:
     """Convert a dict into a canonical string representation"""
     return json.dumps(
         item, separators=(",", ":"), ensure_ascii=False, allow_nan=False, sort_keys=True
-    )
+    ).encode()
 
 
 def print_csc(csc: dict) -> str:
@@ -86,12 +95,12 @@ def format_itemwise(csc: SeqCol) -> list:
     return {"sequences": list_of_dicts}
 
 
-def parse_fasta(fa_file) -> pyfaidx.Fasta:
+def parse_fasta(fa_file_path: str) -> pyfaidx.Fasta:
     """
     Read in a gzipped or not gzipped FASTA file
     """
     try:
-        return pyfaidx.Fasta(fa_file)
+        return pyfaidx.Fasta(fa_file_path)
     except pyfaidx.UnsupportedCompressionFormat:
         # pyfaidx can handle bgzip but not gzip; so we just hack it here and
         # gunzip the file into a temporary one and read it in not to interfere
@@ -99,7 +108,9 @@ def parse_fasta(fa_file) -> pyfaidx.Fasta:
         from gzip import open as gzopen
         from tempfile import NamedTemporaryFile
 
-        with gzopen(fa_file, "rt") as f_in, NamedTemporaryFile(mode="w+t", suffix=".fa") as f_out:
+        with gzopen(fa_file_path, "rt") as f_in, NamedTemporaryFile(
+            mode="w+t", suffix=".fa"
+        ) as f_out:
             f_out.writelines(f_in.read())
             f_out.seek(0)
             return pyfaidx.Fasta(f_out.name)
@@ -134,10 +145,10 @@ def chrom_sizes_to_seqcol(
     return CSC
 
 
-def fasta_file_to_digest(fa_file_path: str) -> str:
+def fasta_file_to_digest(fa_file_path: str, schema: dict = None) -> str:
     """Given a fasta, return a digest"""
     seqcol_obj = fasta_file_to_seqcol(fa_file_path)
-    return seqcol_digest(seqcol_obj)
+    return seqcol_digest(seqcol_obj, schema)
 
 
 def fasta_file_to_seqcol(fa_file_path: str) -> dict:
@@ -180,7 +191,9 @@ def fasta_obj_to_seqcol(
     return CSC
 
 
-def build_sorted_name_length_pairs(obj: dict, digest_function):
+def build_sorted_name_length_pairs(
+    obj: dict, digest_function: Callable[[str], str] = sha512t24u_digest
+):
     """Builds the sorted_name_length_pairs attribute, which corresponds to the coordinate system"""
     sorted_name_length_pairs = []
     for i in range(len(obj["names"])):
@@ -193,7 +206,7 @@ def build_sorted_name_length_pairs(obj: dict, digest_function):
     return nl_digests
 
 
-def compare_seqcols(A: SeqCol, B: SeqCol):
+def compare_seqcols(A: SeqCol, B: SeqCol) -> dict:
     """
     Workhorse comparison function
 
@@ -243,7 +256,7 @@ def compare_seqcols(A: SeqCol, B: SeqCol):
     return return_obj
 
 
-def _compare_elements(A: list, B: list):
+def _compare_elements(A: list, B: list) -> dict:
     """
     Compare elements between two arrays. Helper function for individual elements used by workhorse compare_seqcols function
     """
diff --git a/seqcolapi/__init__.py b/seqcolapi/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/seqcolapi/__main__.py b/seqcolapi/__main__.py
new file mode 100644
index 0000000..2e4396a
--- /dev/null
+++ b/seqcolapi/__main__.py
@@ -0,0 +1,9 @@
+import sys
+from .main import main
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except KeyboardInterrupt:
+        print("Program canceled by user")
+        sys.exit(1)
diff --git a/seqcolapi/_version.py b/seqcolapi/_version.py
new file mode 100644
index 0000000..f102a9c
--- /dev/null
+++ b/seqcolapi/_version.py
@@ -0,0 +1,1 @@
+__version__ = "0.0.1"
diff --git a/seqcolapi/const.py b/seqcolapi/const.py
new file mode 100644
index 0000000..ddd5504
--- /dev/null
+++ b/seqcolapi/const.py
@@ -0,0 +1,17 @@
+import os
+
+from refget._version import __version__ as refget_pkg_version
+from platform import python_version
+
+from ._version import __version__ as seqcolapi_version
+
+PKG_NAME = "seqcolapi"
+ALL_VERSIONS = {
+    "seqcolapi_version": seqcolapi_version,
+    "refget_pkg_version": refget_pkg_version,
+    "python_version": python_version(),
+    "seqcol_spec_version": "0.1.0",
+}
+STATIC_DIRNAME = "static"
+STATIC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), STATIC_DIRNAME)
+TEMPLATES_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "templates")
diff --git a/seqcolapi/examples.py b/seqcolapi/examples.py
new file mode 100644
index 0000000..2704252
--- /dev/null
+++ b/seqcolapi/examples.py
@@ -0,0 +1,143 @@
+# Models
+# Used for documentation examples in OpenAPI
+
+from fastapi import Path, Body
+
+example_digest = Path(
+    ...,
+    description="Sequence collection digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="a6748aa0f6a1e165f871dbed5e54ba62",
+)
+
+example_digest_2 = Path(
+    ...,
+    description="Sequence collection digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="2786eb8a921aa97018c214f64b9960a0",
+)
+
+example_digest_hg38 = Path(
+    ...,
+    description="Sequence collection digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="514c871928a74885ce981faa61ccbb1a",
+)
+
+example_digest_hg38_primary = Path(
+    ...,
+    description="Sequence collection digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="c345e091cce0b1df78bfc124b03fba1c",
+)
+
+example_sequence = Path(
+    ...,
+    description="Refget sequence digest",
+    pattern=r"^[-\w]+$",
+    max_length=64,
+    min_length=32,
+    examples="76f9f3315fa4b831e93c36cd88196480",
+)
+
+example_hg38_sc = Body(
+    {
+        "lengths": [
+            "248956422",
+            "242193529",
+            "198295559",
+            "190214555",
+            "181538259",
+            "170805979",
+            "159345973",
+            "145138636",
+            "138394717",
+            "133797422",
+            "135086622",
+            "133275309",
+            "114364328",
+            "107043718",
+            "101991189",
+            "90338345",
+            "83257441",
+            "80373285",
+            "58617616",
+            "64444167",
+            "46709983",
+            "50818468",
+            "16569",
+            "156040895",
+            "57227415",
+        ],
+        "names": [
+            "chr1",
+            "chr2",
+            "chr3",
+            "chr4",
+            "chr5",
+            "chr6",
+            "chr7",
+            "chr8",
+            "chr9",
+            "chr10",
+            "chr11",
+            "chr12",
+            "chr13",
+            "chr14",
+            "chr15",
+            "chr16",
+            "chr17",
+            "chr18",
+            "chr19",
+            "chr20",
+            "chr21",
+            "chr22",
+            "chrM",
+            "chrX",
+            "chrY",
+        ],
+        "sequences": [
+            "a004bc1b0bf05fc668cab6bbfd93d3eb",
+            "0ccf3a67666ac53f99fcad19768f2dde",
+            "bda7b228789169ae811dd8d676d517ca",
+            "88a6091e2d9a609f4ea7eaef937cd4c2",
+            "0f1725f15e8046a6a04e32de629b1e10",
+            "08c3702d62a2c476a081d3ccd15ea30c",
+            "cac9e313d08cdf40c9eeafe62b17879a",
+            "9a2ebb88dc34c2af023d50219248c815",
+            "41bbec590d36e711864dc6f030f0264b",
+            "6b420cbb22daea77d7cc930c0a00f812",
+            "0d4e0be5c4e5bc0f12912894f21a5dd8",
+            "e1507ba70028a65b3f5a81b594e6f0fe",
+            "7110500758388b169fe631b212b7e56c",
+            "f37e77fdbacb1a0f1be5e2bf25df343d",
+            "3f14ce1984dada290682eb1f564934ee",
+            "88169bd58f0c5f9fd083030d1357d908",
+            "0bbc162a7d963574b5989adab5651ac5",
+            "388e8c7cd11a23eebf84a02d5e442bb7",
+            "1c927775585df1cb09ec7c7dd1b32a6a",
+            "c37960f60eff5e2cfbde87e53d262efa",
+            "f0324d60ccf85288a26a47a7ca25a54a",
+            "f7479d5a2a3169e2e44d97d7f2a13db1",
+            "6ab1f3c8f4941e148463c40408c89e43",
+            "6bdaf93397b486a58fd60b55aa2e21ca",
+            "9bd609da53b41a50a724f2a0131ee9c1",
+        ],
+    }
+)
+
+reclimit_ex = Path(
+    ...,
+    description="Recursion limit, the number of times to recurse to populate digests in the structure",
+    gt=-1,
+    lt=2,
+    examples=0,
+)
diff --git a/seqcolapi/main.py b/seqcolapi/main.py
new file mode 100644
index 0000000..dedbabb
--- /dev/null
+++ b/seqcolapi/main.py
@@ -0,0 +1,161 @@
+import henge
+import json
+import logging
+import os
+import sys
+import uvicorn
+import yacman
+
+from fastapi import Body, FastAPI, Response
+from fastapi import HTTPException
+from fastapi.middleware.cors import CORSMiddleware
+from pydantic import BaseModel, Field
+from fastapi.responses import JSONResponse, FileResponse
+from starlette.requests import Request
+from starlette.templating import Jinja2Templates
+from starlette.staticfiles import StaticFiles
+from typing import Union
+
+from .const import *
+from .scconf import RDBDict
+from .examples import *
+
+from refget import SeqColHenge, format_itemwise
+from yacman import select_config, FutureYAMLConfigManager as YAMLConfigManager
+
+
+class SeqColConf(YAMLConfigManager):
+    pass
+
+
+global _LOGGER
+
+_LOGGER = logging.getLogger(__name__)
+
+templates = Jinja2Templates(directory=TEMPLATES_PATH)
+
+for key, value in ALL_VERSIONS.items():
+    _LOGGER.info(f"{key}: {value}")
+
+
+app = FastAPI(
+    title="Sequence Collections API",
+    description="An API providing metadata such as names, lengths, and other values for collections of reference sequences",
+    version=seqcolapi_version,
+)
+
+from refget import seqcol_router
+
+app.include_router(seqcol_router)
+
+origins = ["*"]
+
+app.add_middleware(  # This is a public API, so we allow all origins
+    CORSMiddleware,
+    allow_origins=origins,
+    allow_credentials=True,
+    allow_methods=["*"],
+    allow_headers=["*"],
+)
+
+
+@app.get("favicon.ico", include_in_schema=False)
+async def favicon():
+    return FileResponse(f"/static/favicon.ico")
+
+
+@app.get("/", summary="Home page", tags=["General endpoints"])
+async def index(request: Request):
+    """
+    Returns a landing page HTML with the server resources ready to download. No inputs required.
+    """
+    templ_vars = {"request": request, "openapi_version": app.openapi()["openapi"]}
+    _LOGGER.debug("merged vars: {}".format(dict(templ_vars, **ALL_VERSIONS)))
+    return templates.TemplateResponse("index.html", dict(templ_vars, **ALL_VERSIONS))
+
+
+@app.get("/service-info", summary="GA4GH service info", tags=["General endpoints"])
+async def service_info():
+    ret = {
+        "id": "org.databio.seqcolapi",
+        "name": "Sequence collections",
+        "type": {
+            "group": "org.ga4gh",
+            "artifact": "refget.seqcol",
+            "version": ALL_VERSIONS["seqcol_spec_version"],
+        },
+        "description": "An API providing metadata such as names, lengths, and other values for collections of reference sequences",
+        "organization": {"name": "Databio Lab", "url": "https://databio.org"},
+        "contactUrl": "https://github.com/refgenie/seqcol/issues",
+        "documentationUrl": "https://seqcolapi.databio.org",
+        "updatedAt": "2021-03-01T00:00:00Z",
+        "environment": "dev",
+        "version": ALL_VERSIONS["seqcolapi_version"],
+        "seqcol": {"schema": schenge.schemas, "sorted_name_length_pairs": True},
+    }
+    return JSONResponse(content=ret)
+
+
+# Mount statics after other routes for lower precedence
+app.mount(f"/", StaticFiles(directory=STATIC_PATH), name=STATIC_DIRNAME)
+
+
+def create_globals(scconf: yacman.YAMLConfigManager):
+    """
+    Create global variables for the app to use.
+    """
+    print(scconf)
+    _LOGGER.info(f"Connecting to database... {scconf.exp['database']['host']}")
+    global schenge
+
+    pgdb = RDBDict(
+        db_name=scconf.exp["database"]["name"],
+        db_user=scconf.exp["database"]["user"],
+        db_password=scconf.exp["database"]["password"],
+        db_host=scconf.exp["database"]["host"],
+        db_port=scconf.exp["database"]["port"],
+        db_table=scconf.exp["database"]["table"],
+    )
+    _LOGGER.info(f"Using schema: {scconf['schemas']}")
+    schenge = SeqColHenge(
+        database=pgdb,
+        schemas=scconf["schemas"],
+    )
+
+    return schenge
+
+
+def main(injected_args=None):
+    # Entry point for running from console_scripts, installed package
+    parser = build_parser()
+    # parser = logmuse.add_logging_options(parser)
+    args = parser.parse_args()
+    if injected_args:
+        args.__dict__.update(injected_args)
+    if not args.command:
+        parser.print_help()
+        print("No subcommand given")
+        sys.exit(1)
+
+    # _LOGGER = logmuse.logger_via_cli(args, make_root=True)
+    _LOGGER.info(f"args: {args}")
+    if "config" in args and args.config is not None:
+        scconf = SeqColConf.from_yaml_file(args.config)
+        create_globals(scconf)
+        app.state.schenge = schenge
+        port = args.port or scconf.exp["server"]["port"]
+        _LOGGER.info(f"Running on port {port}")
+        uvicorn.run(app, host=scconf.exp["server"]["host"], port=port)
+    else:
+        _LOGGER.error("Configure by passing -c SEQCOLAPI_CONFIG ")
+
+
+if __name__ != "__main__":
+    # Entrypoint for running through uvicorn CLI (dev)
+    if os.environ.get("SEQCOLAPI_CONFIG") is not None:
+        _LOGGER.info(f"Loading config from SEQCOLAPI_CONFIG: {os.environ.get('SEQCOLAPI_CONFIG')}")
+        scconf = SeqColConf.from_yaml_file(os.environ.get("SEQCOLAPI_CONFIG"))
+        create_globals(scconf)
+        app.state.schenge = schenge
+    else:
+        _LOGGER.error("Configure by setting SEQCOLAPI_CONFIG env var")
diff --git a/seqcolapi/requirements/requirements-seqcolapi.txt b/seqcolapi/requirements/requirements-seqcolapi.txt
new file mode 100644
index 0000000..d9997e6
--- /dev/null
+++ b/seqcolapi/requirements/requirements-seqcolapi.txt
@@ -0,0 +1,10 @@
+aiofiles
+fastapi
+henge>=0.2.1
+jinja2
+pipestat
+psycopg2-binary
+refget
+uvicorn>=0.7.1
+ubiquerg>=0.6.1
+yacman>=0.9.0
diff --git a/seqcolapi/scconf.py b/seqcolapi/scconf.py
new file mode 100644
index 0000000..6d42259
--- /dev/null
+++ b/seqcolapi/scconf.py
@@ -0,0 +1,341 @@
+import logging
+import os
+import psycopg2
+
+from collections.abc import Mapping
+from psycopg2 import OperationalError, sql
+from psycopg2.errors import UniqueViolation
+
+_LOGGER = logging.getLogger(__name__)
+
+# Use like:
+# pgdb = RDBDict(...)       # Open connection
+# pgdb["key"] = "value"     # Insert item
+# pgdb["key"]               # Retrieve item
+# pgdb.close()              # Close connection
+
+
+def getenv(varname):
+    """Simple wrapper to make the Exception more informative for missing env var"""
+    try:
+        return os.environ[varname]
+    except KeyError:
+        raise Exception(f"Environment variable {varname} not set.")
+
+
+import pipestat
+
+
+class PipestatMapping(pipestat.PipestatManager):
+    """A wrapper class to allow using a PipestatManager as a dict-like object."""
+
+    def __getitem__(self, key):
+        # This little hack makes this work with `in`;
+        # e.g.: for x in rdbdict, which is now disabled, instead of infinite.
+        if isinstance(key, int):
+            raise IndexError
+        return self.retrieve(key)
+
+    def __setitem__(self, key, value):
+        return self.insert({key: value})
+
+    def __len__(self):
+        return self.count_records()
+
+    def _next_page(self):
+        self._buf["page_index"] += 1
+        limit = self._buf["page_size"]
+        offset = self._buf["page_index"] * limit
+        self._buf["keys"] = self.get_records(limit, offset)
+        return self._buf["keys"][0]
+
+    def __iter__(self):
+        _LOGGER.debug("Iterating...")
+        self._buf = {  # buffered iterator
+            "current_view_index": 0,
+            "len": len(self),
+            "page_size": 100,
+            "page_index": -1,
+            "keys": self._next_page(),
+        }
+        return self
+
+    def __next__(self):
+        if self._buf["current_view_index"] > self._buf["len"]:
+            raise StopIteration
+
+        idx = self._buf["current_view_index"] - self._buf["page_index"] * self._buf["page_size"]
+        if idx <= self._buf["page_size"]:
+            self._buf["current_view_index"] += 1
+            return self._buf["keys"][idx - 1]
+        else:  # current index is beyond current page, but not beyond total
+            return self._next_page()
+
+
+class RDBDict(Mapping):
+    """
+    A Relational DataBase Dict.
+
+    Simple database connection manager object that allows us to use a
+    PostgresQL database as a simple key-value store to back Python
+    dict-style access to database items.
+    """
+
+    def __init__(
+        self,
+        db_name: str = None,
+        db_user: str = None,
+        db_password: str = None,
+        db_host: str = None,
+        db_port: str = None,
+        db_table: str = None,
+    ):
+        self.connection = None
+        self.db_name = db_name or getenv("POSTGRES_DB")
+        self.db_user = db_user or getenv("POSTGRES_USER")
+        self.db_host = db_host or os.environ.get("POSTGRES_HOST") or "localhost"
+        self.db_port = db_port or os.environ.get("POSTGRES_PORT") or "5432"
+        self.db_table = db_table or os.environ.get("POSTGRES_TABLE") or "seqcol"
+        db_password = db_password or getenv("POSTGRES_PASSWORD")
+
+        try:
+            self.connection = self.create_connection(
+                self.db_name, self.db_user, db_password, self.db_host, self.db_port
+            )
+            if not self.connection:
+                raise Exception("Connection failed")
+        except Exception as e:
+            _LOGGER.info(f"{self}")
+            raise e
+        _LOGGER.info(self.connection)
+        self.connection.autocommit = True
+
+    def __repr__(self):
+        return (
+            "RDBD object\n"
+            + "db_table: {}\n".format(self.db_table)
+            + "db_name: {}\n".format(self.db_name)
+            + "db_user: {}\n".format(self.db_user)
+            + "db_host: {}\n".format(self.db_host)
+            + "db_port: {}\n".format(self.db_port)
+        )
+
+    def init_table(self):
+        # Wrap statements to prevent SQL injection attacks
+        stmt = sql.SQL(
+            """
+            CREATE TABLE IF NOT EXISTS {table}(
+            key TEXT PRIMARY KEY, 
+            value TEXT);
+        """
+        ).format(table=sql.Identifier(self.db_table))
+        return self.execute_query(stmt, params=None)
+
+    def insert(self, key, value):
+        stmt = sql.SQL(
+            """
+            INSERT INTO {table}(key, value)
+            VALUES (%(key)s, %(value)s);
+        """
+        ).format(table=sql.Identifier(self.db_table))
+        params = {"key": key, "value": value}
+        return self.execute_query(stmt, params)
+
+    def update(self, key, value):
+        stmt = sql.SQL(
+            """
+            UPDATE {table} SET value=%(value)s WHERE key=%(key)s
+        """
+        ).format(table=sql.Identifier(self.db_table))
+        params = {"key": key, "value": value}
+        return self.execute_query(stmt, params)
+
+    def __getitem__(self, key):
+        # This little hack makes this work with `in`;
+        # e.g.: for x in rdbdict, which is now disabled, instead of infinite.
+        if isinstance(key, int):
+            raise IndexError
+        stmt = sql.SQL(
+            """
+            SELECT value FROM {table} WHERE key=%(key)s
+        """
+        ).format(table=sql.Identifier(self.db_table))
+        params = {"key": key}
+        res = self.execute_read_query(stmt, params)
+        if not res:
+            _LOGGER.info("Not found: {}".format(key))
+        return res
+
+    def __setitem__(self, key, value):
+        try:
+            return self.insert(key, value)
+        except UniqueViolation as e:
+            _LOGGER.info("Updating existing value for {}".format(key))
+            return self.update(key, value)
+
+    def __delitem__(self, key):
+        stmt = sql.SQL(
+            """
+            DELETE FROM {table} WHERE key=%(key)s
+        """
+        ).format(table=sql.Identifier(self.db_table))
+        params = {"key": key}
+        res = self.execute_query(stmt, params)
+        return res
+
+    def create_connection(self, db_name, db_user, db_password, db_host, db_port):
+        connection = None
+        try:
+            connection = psycopg2.connect(
+                database=db_name,
+                user=db_user,
+                password=db_password,
+                host=db_host,
+                port=db_port,
+            )
+            _LOGGER.info("Connection to PostgreSQL DB successful")
+        except OperationalError as e:
+            _LOGGER.info("Error: {e}".format(e=str(e)))
+        return connection
+
+    def execute_read_query(self, query, params=None):
+        cursor = self.connection.cursor()
+        result = None
+        try:
+            cursor.execute(query, params)
+            result = cursor.fetchone()
+            if result:
+                return result[0]
+            else:
+                _LOGGER.debug(f"Query: {query}")
+                _LOGGER.debug(f"Result: {result}")
+                return None
+        except OperationalError as e:
+            _LOGGER.info("Error: {e}".format(e=str(e)))
+            raise Exception
+            return None
+        except TypeError as e:
+            _LOGGER.info("TypeError: {e}, item: {q}".format(e=str(e), q=query))
+            raise Exception
+            return None
+
+    def execute_multi_query(self, query, params=None):
+        cursor = self.connection.cursor()
+        result = None
+        try:
+            cursor.execute(query, params)
+            result = cursor.fetchall()
+            return result
+        except OperationalError as e:
+            _LOGGER.info("Error: {e}".format(e=str(e)))
+            raise Exception
+            return None
+        except TypeError as e:
+            pri_LOGGER.infont("TypeError: {e}, item: {q}".format(e=str(e), q=query))
+            raise Exception
+            return None
+
+    def execute_query(self, query, params=None):
+        cursor = self.connection.cursor()
+        try:
+            return cursor.execute(query, params)
+            _LOGGER.info("Query executed successfully")
+        except OperationalError as e:
+            _LOGGER.info("Error: {e}".format(e=str(e)))
+
+    def close(self):
+        _LOGGER.info("Closing connection")
+        return self.connection.close()
+
+    def __del__(self):
+        if self.connection:
+            self.close()
+
+    def __len__(self):
+        stmt = sql.SQL(
+            """
+            SELECT COUNT(*) FROM {table}
+        """
+        ).format(table=sql.Identifier(self.db_table))
+        print(stmt)
+        res = self.execute_read_query(stmt)
+        return res
+
+    def get_paged_keys(self, limit=None, offset=None):
+        stmt_str = "SELECT key FROM {table}"
+        if limit:
+            stmt_str += f" LIMIT {limit}"
+        if offset != None:
+            stmt_str += f" OFFSET {offset}"
+        stmt = sql.SQL(stmt_str).format(table=sql.Identifier(self.db_table))
+        res = self.execute_multi_query(stmt)
+        return res
+
+    def _next_page(self):
+        self._buf["page_index"] += 1
+        limit = self._buf["page_size"]
+        offset = self._buf["page_index"] * limit
+        self._buf["keys"] = self.get_paged_keys(limit, offset)
+        return self._buf["keys"][0]
+
+    def __iter__(self):
+        _LOGGER.debug("Iterating...")
+        self._buf = {  # buffered iterator
+            "current_view_index": 0,
+            "len": len(self),
+            "page_size": 10,
+            "page_index": 0,
+            "keys": self.get_paged_keys(10, 0),
+        }
+        return self
+
+    def __next__(self):
+        if self._buf["current_view_index"] > self._buf["len"]:
+            raise StopIteration
+
+        idx = self._buf["current_view_index"] - self._buf["page_index"] * self._buf["page_size"]
+        if idx <= self._buf["page_size"]:
+            self._buf["current_view_index"] += 1
+            return self._buf["keys"][idx - 1]
+        else:  # current index is beyond current page, but not beyond total
+            return self._next_page()
+
+    # Old, non-paged iterator:
+    # def __iter__(self):
+    #     self._current_idx = 0
+    #     return self
+
+    # def __next__(self):
+    #     stmt = sql.SQL(
+    #         """
+    #         SELECT key,value FROM {table} LIMIT 1 OFFSET %(idx)s
+    #     """
+    #     ).format(table=sql.Identifier(self.db_table))
+    #     res = self.execute_read_query(stmt, {"idx": self._current_idx})
+    #     self._current_idx += 1
+    #     if not res:
+    #         _LOGGER.info("Not found: {}".format(self._current_idx))
+    #         raise StopIteration
+    #     return res
+
+
+# We don't need the full SeqColHenge,
+# which also has loading capability, and requires pyfaidx, which requires
+# biopython, which requires numpy, which is huge and can't compile the in
+# default fastapi container.
+# So, I had written the below class which provides retrieve only.
+# HOWEVER, switching from alpine to slim allows install of numpy;
+# This inflates the container size from 262Mb to 350Mb; perhaps that's worth paying.
+# So I can avoid duplicating this and just use the full SeqColHenge from seqcol
+# class SeqColHenge(refget.RefGetClient):
+#     def retrieve(self, druid, reclimit=None, raw=False):
+#         try:
+#             return super(SeqColHenge, self).retrieve(druid, reclimit, raw)
+#         except henge.NotFoundException as e:
+#             _LOGGER.debug(e)
+#             try:
+#                 return self.refget(druid)
+#             except Exception as e:
+#                 _LOGGER.debug(e)
+#                 raise e
+#                 return henge.NotFoundException("{} not found in database, or in refget.".format(druid))
diff --git a/seqcolapi/static/css/databio.css b/seqcolapi/static/css/databio.css
new file mode 100644
index 0000000..c420865
--- /dev/null
+++ b/seqcolapi/static/css/databio.css
@@ -0,0 +1,179 @@
+
+/* Stuff added by Nathan */
+
+.mail:before {
+    content: attr(data-website) "\0040" attr(data-user);
+    unicode-bidi: bidi-override;
+    direction: rtl;
+	font-weight:bold;
+}
+
+.box {
+	margin-top: 8px;
+	margin-bottom: 8px;
+	/*margin-left: 12px;*/
+	/*margin-right: 12px;*/
+	padding:10px;
+	border: 1px dashed #CCCCFF;
+	background-color:#FFF;
+}
+
+.person {
+	float:left;
+	width: 50%;
+}
+
+.person img {
+	float:left;
+	height: 140px;
+	margin-right:10px;
+	margin-bottom:10px;
+	border: 1px solid #777777;
+}
+
+.persontext {
+	margin:3px;
+}
+
+.col2 {
+   float: left;
+   width: 50%;
+}
+
+.col2r {
+   float: right;
+   width: 50%;
+}
+
+.box h2 {
+	width:100%;
+	clear:both;
+	float:left;
+}
+.title {
+	color:#224477;
+	font-size:1.2em;
+	font-weight:bold;
+}
+
+.publications li {
+	margin: 18px 0 0 0;
+}
+
+.bullet {
+	margin-bottom: 3px;
+	vertical-align: middle;
+	display: inline-block;
+    > svg {
+        display: inline-block;
+        width: 24px;
+        height: 22px;
+        vertical-align: middle;
+
+        path {
+            fill: #000;
+        }
+    }
+}
+
+.quickbox {
+	float:right; text-align:right; border-left: 1px solid #CCC; padding:15px; 
+	margin:0px 0px 0px 6px;
+}
+.quickbox ul {
+    list-style-type: none;
+	padding-top:7px;
+}
+
+.iconlist, .iconlist ul {
+    list-style-type: none;
+	padding-top:0px;
+	margin-left: 6px;
+}
+
+.iconlist li {
+    list-style-type: none;
+	padding:10px 1px 1px 1px;
+	margin: 0px;
+}
+
+.compact {
+	font-size:0.8em;
+}
+
+.compact_title {
+	color:#224477;
+	font-weight:normal;
+}
+
+.category {
+	background-color:#335588; 
+/*	background-color:#117799; */
+	color:white;
+	font-size:14px;
+	font-style:normal;
+	font-weight:bold;
+	text-align:right;
+	padding:5px;
+	margin-bottom:4px;
+}
+
+.thumbnail-left {
+	background-color:#EDF4F2;
+	border-top-width: 1px;
+    border-right-width: 1px;
+    border-bottom-width: 1px;
+    border-left-width: 1px;
+    border-top-style: solid;
+    border-right-style: solid;
+    border-bottom-style: solid;
+    border-left-style: solid;
+	border-top-color: rgb(105, 105, 105);
+    border-right-color: rgb(105, 105, 105);
+    border-bottom-color: rgb(105, 105, 105);
+	border-left-color: rgb(105, 105, 105);
+	padding:3px;
+	margin-right:6px;
+	width:120px;
+	float:left;
+}
+
+.thumbnail-right {
+	background-color:#555555;
+	border-top-width: 1px;
+    border-right-width: 1px;
+    border-bottom-width: 1px;
+    border-left-width: 1px;
+    border-top-style: solid;
+    border-right-style: solid;
+    border-bottom-style: solid;
+    border-left-style: solid;
+	border-top-color: rgb(105, 105, 105);
+    border-right-color: rgb(105, 105, 105);
+    border-bottom-color: rgb(105, 105, 105);
+	border-left-color: rgb(105, 105, 105);
+	margin-left:3px;
+	padding:3px;
+	width:120px;
+	float:right;
+}
+.thumbnail-right img, .thumbnail-left img {
+	display: block;
+}
+
+a {
+    color: #0d6efd;
+    text-decoration: none;
+}
+
+footer ul {
+	display: flex;
+}
+
+footer ul li {
+	padding-left: 8px;
+	padding-right: 8px;
+	list-style: none;
+	display: flex;
+	flex-wrap: wrap;
+}
\ No newline at end of file
diff --git a/seqcolapi/static/css/style.css b/seqcolapi/static/css/style.css
new file mode 100644
index 0000000..cf37b98
--- /dev/null
+++ b/seqcolapi/static/css/style.css
@@ -0,0 +1,157 @@
+html,
+body {
+  height: 100%;
+}
+
+#vertical {
+    padding: 5px;
+}
+
+#main {
+  overflow: auto;
+  padding-bottom: 40px;
+  padding-top: 20px;
+  /* must be same height as the footer */
+}
+
+#footer {
+  position: relative;
+  margin-top: -40px;
+  /* negative value of footer height */
+  height: 40px;
+  padding-top: 5px;
+  padding-left: 10px;
+}
+
+.divider-15 {
+  /* adds spacing 15px */
+  width:90%;
+  min-height:1px;
+  margin-top:15px;
+  margin-bottom:15px;
+  margin-left:15px;
+  display:inline-block;
+  position:relative;
+}
+
+.divider-vertical {
+  margin-top:15px;
+  /*margin-bottom:15px;*/
+}
+
+span {
+  margin-left: 5px;
+}
+
+div.col-auto {
+  padding-left: 10px;
+  padding-right: 0px;
+}
+
+label.col-form-label {
+  padding-bottom: 0px;
+  padding-top: 0px;
+}
+
+.nav-item {
+  color: white;
+  font-size: 1rem;
+  }
+
+.nav-link {
+  color: white;
+  }
+
+.left_footer {
+  width: 40%;
+  float: left;
+  text-align:left;
+  display: inline-block;
+}
+
+.right_footer {
+  width: 40%;
+  float: right;
+  text-align:right;
+  display: inline-block;
+}
+
+.center_footer {
+  width: 20%;
+  overflow: hidden;
+  display: inline-block;
+  text-align: center;
+}
+
+.wrapper {
+  padding-left: 30px;
+  padding-right: 30px;
+  clear: both;
+  position: relative;
+  overflow: hidden;
+}
+
+div#navbar_links {
+  display: flex;
+}
+
+div.col-12#genome-asset {
+    margin: auto;
+    max-width: 1400px;
+}
+
+div.col-12#txt {
+    margin: auto;
+    max-width: 1400px;
+}
+
+.asset_name {
+    width: 200px;
+}
+
+.asset_desc {
+    width: 500px;
+    min-width: 250px;
+}
+
+.actions {
+    min-width: 180px;
+    width: 180px;
+}
+
+.size {
+    width: 150px;
+    min-width: 150px;
+}
+
+.checksum {
+    width: 280px;
+    min-width: 280px;
+}
+
+.container {
+    max-width: none;
+}
+
+th.footer {
+  font-size:12px;
+  padding: 3px;
+  font-weight: bold;
+  text-align: center;
+  background-color: #464c56;
+  color: white;
+  min-width: 90px;
+}
+
+td.footer {
+  font-size:12px;
+  padding: 3px;
+  text-align: center;
+  color: #464c56;
+  font-weight: bold;
+  font-family: Courier New;
+}
+
+code.footer {
+  color:#464c56;
+}
diff --git a/seqcolapi/static/favicon.ico b/seqcolapi/static/favicon.ico
new file mode 100644
index 0000000..117bca4
Binary files /dev/null and b/seqcolapi/static/favicon.ico differ
diff --git a/seqcolapi/static/links_demo.html b/seqcolapi/static/links_demo.html
new file mode 100644
index 0000000..a192233
--- /dev/null
+++ b/seqcolapi/static/links_demo.html
@@ -0,0 +1,269 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+  	
+    <!-- Required meta tags -->
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Sequence Collections API</title>
+  	
+  </head>
+  <body>
+		
+		<nav class="navbar navbar-expand-md py-2 mb-4 border-bottom navbar-light" aria-label="navbar" style="background-color: #EFF3F6;">
+		  <div class="container">
+		    <a href="/" class="align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
+		      <img src="/seqcol_logo.svg" alt="Sequence Collections" height="40"> Sequence collections
+		    </a>
+		    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+		      <span class="navbar-toggler-icon"></span>
+		    </button>
+		    <div class="collapse navbar-collapse me-auto" id="navbarSupportedContent">
+		      <ul class="navbar-nav ms-auto mb-2 mb-sm-0">        
+		      <li class="nav-item mx-2 my-0 h5">
+		        <a class="nav-link" href="/docs">API docs</a>
+		      </li>
+		      <li class="nav-item mx-2 my-0 h5">
+		      <a class="nav-link" href="https://github.com/refgenie/seqcol" target="_blank"><i class="fa fa-2x fa-github" aria-hidden="true"></i>GitHub</a>
+		      <li>
+		      </ul>
+		    </div>
+		  </div>
+		</nav>
+    
+    <div class="container">
+    
+<h3>Sequence collection comparison matrix</h3>
+
+The square matrix below lists sequence collections on the x and y axes. At the intersection is a link to the /comparison endpoint that compares those two genomes.
+
+<style>
+th.rotated-text {
+    height: 200px;
+    white-space: nowrap;
+    padding: 0 !important;
+}
+
+th.rotated-text > div {
+    transform:
+        translate(13px, 0px)
+        rotate(310deg);
+    width: 20px;
+}
+
+th.rotated-text > div > span {
+    padding: 5px 10px;
+}
+</style>
+
+<table class="table mt-5">
+<thead>
+  <th></th>
+  <th class="rotated-text"><div><span>demo0</span></div></th>
+  <th class="rotated-text"><div><span>demo1</span></div></th>
+  <th class="rotated-text"><div><span>demo2</span></div></th>
+  <th class="rotated-text"><div><span>demo3</span></div></th>
+  <th class="rotated-text"><div><span>demo4</span></div></th>
+  <th class="rotated-text"><div><span>demo5</span></div></th>
+  <th class="rotated-text"><div><span>demo6</span></div></th>
+  
+</thead><tr>
+  <th><a href="/collection/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">demo0</a></th>
+
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM">demo1</a></th>
+
+	
+    <td><a href="/comparison/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa">Compare</a></td>
+	
+	
+    <td><a href="/comparison/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2">Compare</a></td>
+	
+	
+    <td><a href="/comparison/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g">Compare</a></td>
+	
+	
+    <td><a href="/comparison/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW">Compare</a></td>
+	
+	
+    <td><a href="/comparison/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa">demo2</a></th>
+
+	
+    <td><a href="/comparison/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+	
+    <td><a href="/comparison/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2">Compare</a></td>
+	
+	
+    <td><a href="/comparison/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g">Compare</a></td>
+	
+	
+    <td><a href="/comparison/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW">Compare</a></td>
+	
+	
+    <td><a href="/comparison/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2">demo3</a></th>
+
+	
+    <td><a href="/comparison/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+	
+    <td><a href="/comparison/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM">Compare</a></td>
+	
+	
+    <td><a href="/comparison/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g">Compare</a></td>
+	
+	
+    <td><a href="/comparison/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW">Compare</a></td>
+	
+	
+    <td><a href="/comparison/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g">demo4</a></th>
+
+	
+    <td><a href="/comparison/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+	
+    <td><a href="/comparison/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM">Compare</a></td>
+	
+	
+    <td><a href="/comparison/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa">Compare</a></td>
+	
+	
+    <td><a href="/comparison/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW">Compare</a></td>
+	
+	
+    <td><a href="/comparison/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW">demo5</a></th>
+
+	
+    <td><a href="/comparison/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+	
+    <td><a href="/comparison/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM">Compare</a></td>
+	
+	
+    <td><a href="/comparison/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa">Compare</a></td>
+	
+	
+    <td><a href="/comparison/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2">Compare</a></td>
+	
+	
+    <td><a href="/comparison/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">demo6</a></th>
+
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/D96Ze37DS8pG-jJXXjyHbUlb9coGht6g">Compare</a></td>
+	
+	
+    <td><a href="/comparison/fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32/JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+</tr>
+
+
+</table>
+
+	</div>
+		
+		<div class="container">
+		  <footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top align-top">
+		  <span class="badge rounded-pill bg-secondary">seqcolapi </span>
+		  <span class="badge rounded-pill bg-secondary">seqcol </span>
+		  <span class="badge rounded-pill bg-secondary">
+		    Python </span>
+
+		  <div class="ms-auto">
+		    <a href="https://databio.org/"><img src="static/logo_databio_long.svg" alt="Sheffield Computational Biology Lab" width="200"></a>
+		  </div>
+			</footer>
+		</div>
+		
+  </body>	
+  	<!-- Bootstrap CSS -->
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
+    <!-- Custom CSS -->
+    <link rel="stylesheet" href="https://databio.org/css/databio.css">
+</html>
\ No newline at end of file
diff --git a/seqcolapi/static/links_ref.html b/seqcolapi/static/links_ref.html
new file mode 100644
index 0000000..b14c71d
--- /dev/null
+++ b/seqcolapi/static/links_ref.html
@@ -0,0 +1,317 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+  	
+    <!-- Required meta tags -->
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Sequence Collections API</title>
+  	
+  </head>
+  <body>
+		
+		<nav class="navbar navbar-expand-md py-2 mb-4 border-bottom navbar-light" aria-label="navbar" style="background-color: #EFF3F6;">
+		  <div class="container">
+		    <a href="/" class="align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
+		      <img src="/seqcol_logo.svg" alt="Sequence Collections" height="40"> Sequence collections
+		    </a>
+		    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+		      <span class="navbar-toggler-icon"></span>
+		    </button>
+		    <div class="collapse navbar-collapse me-auto" id="navbarSupportedContent">
+		      <ul class="navbar-nav ms-auto mb-2 mb-sm-0">        
+		      <li class="nav-item mx-2 my-0 h5">
+		        <a class="nav-link" href="/docs">API docs</a>
+		      </li>
+		      <li class="nav-item mx-2 my-0 h5">
+		      <a class="nav-link" href="https://github.com/refgenie/seqcol" target="_blank"><i class="fa fa-2x fa-github" aria-hidden="true"></i>GitHub</a>
+		      <li>
+		      </ul>
+		    </div>
+		  </div>
+		</nav>
+    
+    <div class="container">
+    
+<h3>Sequence collection comparison matrix</h3>
+
+The square matrix below lists sequence collections on the x and y axes. At the intersection is a link to the /comparison endpoint that compares those two genomes.
+
+<style>
+th.rotated-text {
+    height: 200px;
+    white-space: nowrap;
+    padding: 0 !important;
+}
+
+th.rotated-text > div {
+    transform:
+        translate(13px, 0px)
+        rotate(310deg);
+    width: 20px;
+}
+
+th.rotated-text > div > span {
+    padding: 5px 10px;
+}
+</style>
+
+<table class="table mt-5">
+<thead>
+  <th></th>
+  <th class="rotated-text"><div><span>Ensembl GRCh38 primary assembly</span></div></th>
+  <th class="rotated-text"><div><span>Ensembl GRCh38 toplevel assembly</span></div></th>
+  <th class="rotated-text"><div><span>UCSC hg38</span></div></th>
+  <th class="rotated-text"><div><span>NCBI GCA 000001405.28</span></div></th>
+  <th class="rotated-text"><div><span>chm13v2</span></div></th>
+  <th class="rotated-text"><div><span>chm13v1.1</span></div></th>
+  <th class="rotated-text"><div><span>Refgenie hg38</span></div></th>
+  <th class="rotated-text"><div><span>Refgenie hg38 primary</span></div></th>
+  
+</thead><tr>
+  <th><a href="/collection/3e78fad819a8c3fd92134d34b9b1b489">Ensembl GRCh38 primary assembly</a></th>
+
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/3e78fad819a8c3fd92134d34b9b1b489/5906d7203641c7e051c7b66adec41da9">Compare</a></td>
+	
+	
+    <td><a href="/comparison/3e78fad819a8c3fd92134d34b9b1b489/4f8e053cf97eca7d3b71f50703f9f6c1">Compare</a></td>
+	
+	
+    <td><a href="/comparison/3e78fad819a8c3fd92134d34b9b1b489/54a6f7a145e0abdd0d57add6fd078d23">Compare</a></td>
+	
+	
+    <td><a href="/comparison/3e78fad819a8c3fd92134d34b9b1b489/385ae83a60ff4b87bf57074e00f2cc0d">Compare</a></td>
+	
+	
+    <td><a href="/comparison/3e78fad819a8c3fd92134d34b9b1b489/60392d4e0f530b8d944e61d159b7e774">Compare</a></td>
+	
+	
+    <td><a href="/comparison/3e78fad819a8c3fd92134d34b9b1b489/0cd603fd571c64cfae95742e66be503a">Compare</a></td>
+	
+	
+    <td><a href="/comparison/3e78fad819a8c3fd92134d34b9b1b489/a2da12627e2de9f0ca907f78bb78e492">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/5906d7203641c7e051c7b66adec41da9">Ensembl GRCh38 toplevel assembly</a></th>
+
+	
+    <td><a href="/comparison/5906d7203641c7e051c7b66adec41da9/3e78fad819a8c3fd92134d34b9b1b489">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/5906d7203641c7e051c7b66adec41da9/4f8e053cf97eca7d3b71f50703f9f6c1">Compare</a></td>
+	
+	
+    <td><a href="/comparison/5906d7203641c7e051c7b66adec41da9/54a6f7a145e0abdd0d57add6fd078d23">Compare</a></td>
+	
+	
+    <td><a href="/comparison/5906d7203641c7e051c7b66adec41da9/385ae83a60ff4b87bf57074e00f2cc0d">Compare</a></td>
+	
+	
+    <td><a href="/comparison/5906d7203641c7e051c7b66adec41da9/60392d4e0f530b8d944e61d159b7e774">Compare</a></td>
+	
+	
+    <td><a href="/comparison/5906d7203641c7e051c7b66adec41da9/0cd603fd571c64cfae95742e66be503a">Compare</a></td>
+	
+	
+    <td><a href="/comparison/5906d7203641c7e051c7b66adec41da9/a2da12627e2de9f0ca907f78bb78e492">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/4f8e053cf97eca7d3b71f50703f9f6c1">UCSC hg38</a></th>
+
+	
+    <td><a href="/comparison/4f8e053cf97eca7d3b71f50703f9f6c1/3e78fad819a8c3fd92134d34b9b1b489">Compare</a></td>
+	
+	
+    <td><a href="/comparison/4f8e053cf97eca7d3b71f50703f9f6c1/5906d7203641c7e051c7b66adec41da9">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/4f8e053cf97eca7d3b71f50703f9f6c1/54a6f7a145e0abdd0d57add6fd078d23">Compare</a></td>
+	
+	
+    <td><a href="/comparison/4f8e053cf97eca7d3b71f50703f9f6c1/385ae83a60ff4b87bf57074e00f2cc0d">Compare</a></td>
+	
+	
+    <td><a href="/comparison/4f8e053cf97eca7d3b71f50703f9f6c1/60392d4e0f530b8d944e61d159b7e774">Compare</a></td>
+	
+	
+    <td><a href="/comparison/4f8e053cf97eca7d3b71f50703f9f6c1/0cd603fd571c64cfae95742e66be503a">Compare</a></td>
+	
+	
+    <td><a href="/comparison/4f8e053cf97eca7d3b71f50703f9f6c1/a2da12627e2de9f0ca907f78bb78e492">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/54a6f7a145e0abdd0d57add6fd078d23">NCBI GCA 000001405.28</a></th>
+
+	
+    <td><a href="/comparison/54a6f7a145e0abdd0d57add6fd078d23/3e78fad819a8c3fd92134d34b9b1b489">Compare</a></td>
+	
+	
+    <td><a href="/comparison/54a6f7a145e0abdd0d57add6fd078d23/5906d7203641c7e051c7b66adec41da9">Compare</a></td>
+	
+	
+    <td><a href="/comparison/54a6f7a145e0abdd0d57add6fd078d23/4f8e053cf97eca7d3b71f50703f9f6c1">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/54a6f7a145e0abdd0d57add6fd078d23/385ae83a60ff4b87bf57074e00f2cc0d">Compare</a></td>
+	
+	
+    <td><a href="/comparison/54a6f7a145e0abdd0d57add6fd078d23/60392d4e0f530b8d944e61d159b7e774">Compare</a></td>
+	
+	
+    <td><a href="/comparison/54a6f7a145e0abdd0d57add6fd078d23/0cd603fd571c64cfae95742e66be503a">Compare</a></td>
+	
+	
+    <td><a href="/comparison/54a6f7a145e0abdd0d57add6fd078d23/a2da12627e2de9f0ca907f78bb78e492">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/385ae83a60ff4b87bf57074e00f2cc0d">chm13v2</a></th>
+
+	
+    <td><a href="/comparison/385ae83a60ff4b87bf57074e00f2cc0d/3e78fad819a8c3fd92134d34b9b1b489">Compare</a></td>
+	
+	
+    <td><a href="/comparison/385ae83a60ff4b87bf57074e00f2cc0d/5906d7203641c7e051c7b66adec41da9">Compare</a></td>
+	
+	
+    <td><a href="/comparison/385ae83a60ff4b87bf57074e00f2cc0d/4f8e053cf97eca7d3b71f50703f9f6c1">Compare</a></td>
+	
+	
+    <td><a href="/comparison/385ae83a60ff4b87bf57074e00f2cc0d/54a6f7a145e0abdd0d57add6fd078d23">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/385ae83a60ff4b87bf57074e00f2cc0d/60392d4e0f530b8d944e61d159b7e774">Compare</a></td>
+	
+	
+    <td><a href="/comparison/385ae83a60ff4b87bf57074e00f2cc0d/0cd603fd571c64cfae95742e66be503a">Compare</a></td>
+	
+	
+    <td><a href="/comparison/385ae83a60ff4b87bf57074e00f2cc0d/a2da12627e2de9f0ca907f78bb78e492">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/60392d4e0f530b8d944e61d159b7e774">chm13v1.1</a></th>
+
+	
+    <td><a href="/comparison/60392d4e0f530b8d944e61d159b7e774/3e78fad819a8c3fd92134d34b9b1b489">Compare</a></td>
+	
+	
+    <td><a href="/comparison/60392d4e0f530b8d944e61d159b7e774/5906d7203641c7e051c7b66adec41da9">Compare</a></td>
+	
+	
+    <td><a href="/comparison/60392d4e0f530b8d944e61d159b7e774/4f8e053cf97eca7d3b71f50703f9f6c1">Compare</a></td>
+	
+	
+    <td><a href="/comparison/60392d4e0f530b8d944e61d159b7e774/54a6f7a145e0abdd0d57add6fd078d23">Compare</a></td>
+	
+	
+    <td><a href="/comparison/60392d4e0f530b8d944e61d159b7e774/385ae83a60ff4b87bf57074e00f2cc0d">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/60392d4e0f530b8d944e61d159b7e774/0cd603fd571c64cfae95742e66be503a">Compare</a></td>
+	
+	
+    <td><a href="/comparison/60392d4e0f530b8d944e61d159b7e774/a2da12627e2de9f0ca907f78bb78e492">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/0cd603fd571c64cfae95742e66be503a">Refgenie hg38</a></th>
+
+	
+    <td><a href="/comparison/0cd603fd571c64cfae95742e66be503a/3e78fad819a8c3fd92134d34b9b1b489">Compare</a></td>
+	
+	
+    <td><a href="/comparison/0cd603fd571c64cfae95742e66be503a/5906d7203641c7e051c7b66adec41da9">Compare</a></td>
+	
+	
+    <td><a href="/comparison/0cd603fd571c64cfae95742e66be503a/4f8e053cf97eca7d3b71f50703f9f6c1">Compare</a></td>
+	
+	
+    <td><a href="/comparison/0cd603fd571c64cfae95742e66be503a/54a6f7a145e0abdd0d57add6fd078d23">Compare</a></td>
+	
+	
+    <td><a href="/comparison/0cd603fd571c64cfae95742e66be503a/385ae83a60ff4b87bf57074e00f2cc0d">Compare</a></td>
+	
+	
+    <td><a href="/comparison/0cd603fd571c64cfae95742e66be503a/60392d4e0f530b8d944e61d159b7e774">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+	
+    <td><a href="/comparison/0cd603fd571c64cfae95742e66be503a/a2da12627e2de9f0ca907f78bb78e492">Compare</a></td>
+	
+</tr>
+<tr>
+  <th><a href="/collection/a2da12627e2de9f0ca907f78bb78e492">Refgenie hg38 primary</a></th>
+
+	
+    <td><a href="/comparison/a2da12627e2de9f0ca907f78bb78e492/3e78fad819a8c3fd92134d34b9b1b489">Compare</a></td>
+	
+	
+    <td><a href="/comparison/a2da12627e2de9f0ca907f78bb78e492/5906d7203641c7e051c7b66adec41da9">Compare</a></td>
+	
+	
+    <td><a href="/comparison/a2da12627e2de9f0ca907f78bb78e492/4f8e053cf97eca7d3b71f50703f9f6c1">Compare</a></td>
+	
+	
+    <td><a href="/comparison/a2da12627e2de9f0ca907f78bb78e492/54a6f7a145e0abdd0d57add6fd078d23">Compare</a></td>
+	
+	
+    <td><a href="/comparison/a2da12627e2de9f0ca907f78bb78e492/385ae83a60ff4b87bf57074e00f2cc0d">Compare</a></td>
+	
+	
+    <td><a href="/comparison/a2da12627e2de9f0ca907f78bb78e492/60392d4e0f530b8d944e61d159b7e774">Compare</a></td>
+	
+	
+    <td><a href="/comparison/a2da12627e2de9f0ca907f78bb78e492/0cd603fd571c64cfae95742e66be503a">Compare</a></td>
+	
+	
+	<td>=</td>
+	
+</tr>
+
+
+</table>
+
+	</div>
+		
+		<div class="container">
+		  <footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top align-top">
+		  <span class="badge rounded-pill bg-secondary">seqcolapi </span>
+		  <span class="badge rounded-pill bg-secondary">
+		    Python </span>
+		  <div class="ms-auto">
+		    <a href="https://databio.org/"><img src="/logo_databio_long.svg" alt="Sheffield Computational Biology Lab" width="200"></a>
+		  </div>
+			</footer>
+		</div>
+		
+  </body>	
+  	<!-- Bootstrap CSS -->
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
+    <!-- Custom CSS -->
+    <link rel="stylesheet" href="https://databio.org/css/databio.css">
+</html>
\ No newline at end of file
diff --git a/seqcolapi/static/logo_databio_long.svg b/seqcolapi/static/logo_databio_long.svg
new file mode 100644
index 0000000..d046f99
--- /dev/null
+++ b/seqcolapi/static/logo_databio_long.svg
@@ -0,0 +1,223 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="83.596474mm"
+   height="23.480446mm"
+   viewBox="0 0 83.596475 23.480446"
+   version="1.1"
+   id="svg1360"
+   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
+   sodipodi:docname="logo_databio_long.svg">
+  <defs
+     id="defs1354" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8"
+     inkscape:cx="104.85325"
+     inkscape:cy="19.697612"
+     inkscape:document-units="mm"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     fit-margin-top="2"
+     fit-margin-left="3"
+     fit-margin-right="3"
+     fit-margin-bottom="2"
+     inkscape:window-width="2488"
+     inkscape:window-height="1343"
+     inkscape:window-x="1272"
+     inkscape:window-y="231"
+     inkscape:window-maximized="1" />
+  <metadata
+     id="metadata1357">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-107.88835,-68.261876)">
+    <g
+       aria-label="DATA"
+       style="font-style:normal;font-weight:normal;font-size:12.37311554px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#2c89a0;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       id="text5241">
+      <path
+         d="m 138.55401,76.239631 c 0,-1.237311 -0.4578,-2.363265 -1.41053,-3.167518 -0.90324,-0.75476 -1.89309,-0.965103 -3.04379,-0.965103 h -1.68274 v 8.252869 h 1.67037 c 1.16307,0 2.10343,-0.185597 3.01904,-0.95273 0.97747,-0.816626 1.44765,-1.90546 1.44765,-3.167518 z m -0.92798,0 c 0,0.965103 -0.38357,1.880714 -1.12596,2.511743 -0.68052,0.581536 -1.48477,0.75476 -2.36326,0.75476 h -0.80425 v -6.533005 h 0.80425 c 2.00444,0 3.48922,1.187819 3.48922,3.266502 z"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, ';fill:#2c89a0;fill-opacity:1;stroke-width:0.26458332"
+         id="path834" />
+      <path
+         d="m 146.41091,80.359879 -3.69956,-8.648808 -3.79855,8.648808 h 1.00222 l 0.98985,-2.338519 h 3.52634 l 0.9651,2.338519 z m -2.33852,-3.192264 h -2.79632 l 1.41053,-3.303622 z"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, ';fill:#2c89a0;fill-opacity:1;stroke-width:0.26458332"
+         id="path836" />
+      <path
+         d="M 151.08792,72.973129 V 72.10701 h -4.9245 v 0.866119 h 2.00445 v 7.38675 h 0.91561 v -7.38675 z"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, ';fill:#2c89a0;fill-opacity:1;stroke-width:0.26458332"
+         id="path838" />
+      <path
+         d="m 158.33856,80.359879 -3.69957,-8.648808 -3.79854,8.648808 h 1.00222 l 0.98985,-2.338519 h 3.52634 l 0.9651,2.338519 z m -2.33852,-3.192264 h -2.79633 l 1.41054,-3.303622 z"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, ';fill:#2c89a0;fill-opacity:1;stroke-width:0.26458332"
+         id="path840" />
+    </g>
+    <g
+       aria-label="BIO"
+       style="font-style:normal;font-weight:normal;font-size:12.37311554px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#2ca05a;fill-opacity:1;stroke:none;stroke-width:0.26458332"
+       id="text5245">
+      <path
+         d="m 175.59205,78.254695 c 0,-1.014595 -0.58154,-1.806475 -1.55901,-2.078683 0.54441,-0.39594 0.81662,-0.940357 0.81662,-1.608505 0,-0.643402 -0.25983,-1.299177 -0.76713,-1.719863 -0.51967,-0.433059 -1.21257,-0.519671 -1.86834,-0.519671 h -1.48477 v 8.252868 h 2.05393 c 0.74239,0 1.38579,-0.08661 1.9797,-0.569163 0.53204,-0.433059 0.829,-1.064088 0.829,-1.756983 z m -1.64562,-3.674815 c 0,0.39594 -0.12374,0.816626 -0.43306,1.076461 -0.34645,0.296955 -0.75476,0.309328 -1.17545,0.309328 h -0.69289 v -2.771578 h 0.71764 c 0.94035,0 1.58376,0.35882 1.58376,1.385789 z m 0.73001,3.650069 c 0,0.433059 -0.1856,0.866118 -0.53204,1.138327 -0.39594,0.321701 -0.85375,0.35882 -1.34867,0.35882 h -1.1507 v -2.969548 h 0.94035 c 0.45781,0 0.98985,0.01237 1.39816,0.247463 0.43306,0.247462 0.6929,0.730013 0.6929,1.224938 z"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, ';fill:#2ca05a;stroke-width:0.26458332"
+         id="path843" />
+      <path
+         d="m 178.20276,80.580841 v -8.252868 h -0.91561 v 8.252868 z"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, ';fill:#2ca05a;stroke-width:0.26458332"
+         id="path845" />
+      <path
+         d="m 188.48481,76.460594 c 0,-2.338519 -1.94258,-4.268725 -4.2811,-4.268725 -2.36326,0 -4.30584,1.930206 -4.30584,4.293471 0,2.350892 1.95495,4.243978 4.29347,4.243978 2.33852,0 4.29347,-1.917832 4.29347,-4.268724 z m -0.92798,0 c 0,1.855967 -1.49715,3.402606 -3.36549,3.402606 -1.84359,0 -3.36549,-1.534266 -3.36549,-3.37786 0,-1.880714 1.48478,-3.427353 3.37786,-3.427353 1.86834,0 3.35312,1.546639 3.35312,3.402607 z"
+         style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, ';fill:#2ca05a;stroke-width:0.26458332"
+         id="path847" />
+    </g>
+    <path
+       id="path5247"
+       d="m 166.86512,75.330071 h -1.81958 v -1.819572 c 0,-0.454891 -0.36391,-0.909793 -0.90978,-0.909793 -0.54588,0 -0.90979,0.363922 -0.90979,0.909793 v 1.819572 h -1.81958 c -0.45488,0 -0.90979,0.363922 -0.90979,0.909792 0,0.545872 0.36392,0.909782 0.90979,0.909782 h 1.81958 v 1.819584 c 0,0.545871 0.36391,0.909781 0.90979,0.909781 0.54587,0 0.90978,-0.36391 0.90978,-0.909781 v -1.819584 h 1.81958 c 0.54587,0 0.90978,-0.36391 0.90978,-0.909782 0,-0.54587 -0.36391,-0.909792 -0.90978,-0.909792 z"
+       inkscape:connector-curvature="0"
+       style="fill:#b3b3b3;fill-opacity:1;stroke:none;stroke-width:0.10000001;stroke-miterlimit:4;stroke-dasharray:none" />
+    <g
+       id="g5271"
+       transform="translate(2.012354,-31.924588)">
+      <path
+         sodipodi:type="star"
+         style="opacity:1;vector-effect:none;fill:#2ca05a;fill-opacity:1;stroke:none;stroke-width:0.2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+         id="path5249"
+         sodipodi:sides="6"
+         sodipodi:cx="111.21949"
+         sodipodi:cy="96.672623"
+         sodipodi:r1="9.7402229"
+         sodipodi:r2="4.8701115"
+         sodipodi:arg1="0.78539816"
+         sodipodi:arg2="1.3089969"
+         inkscape:flatsided="true"
+         inkscape:rounded="0"
+         inkscape:randomized="0"
+         d="m 118.10687,103.56 -9.40834,2.52096 -6.88737,-6.887382 2.52095,-9.408333 9.40834,-2.520955 6.88737,6.887377 z"
+         inkscape:transform-center-x="1.5437649"
+         inkscape:transform-center-y="-0.89129289"
+         transform="rotate(-15,172.38384,79.755571)" />
+      <g
+         id="g5265"
+         transform="rotate(-22.024691,117.42466,111.75423)">
+        <g
+           style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99149966"
+           transform="matrix(1.0025367,0.43935458,-0.57881485,0.76098444,29.935936,-23.579547)"
+           id="g5263">
+          <g
+             style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.99149966"
+             id="g5261">
+            <g
+               style="fill:#e6e6e6;stroke:#b3b3b3"
+               id="g1021">
+              <path
+                 sodipodi:nodetypes="ccccccccccccccccccccccccccccc"
+                 inkscape:connector-curvature="0"
+                 id="path5259"
+                 d="m 148.18957,86.566811 c -2.82437,0.30535 -6.81206,1.79976 -8.90162,4.37313 -1.04477,1.28669 -1.69306,2.728248 -1.62023,4.187428 0.0728,1.45918 1.17168,3.327718 2.98327,4.656219 l 0.0943,-0.128123 c -0.99321,-0.728351 -1.50748,-1.491299 -1.78106,-2.267022 1.84548,1.103227 3.71434,1.974623 5.61594,2.37708 -2.05665,2.521717 -5.08803,4.553957 -7.84517,4.852037 l -0.0183,6.3e-4 c 2.82437,-0.30535 6.82097,-1.80007 8.91052,-4.37344 1.04477,-1.286683 1.69306,-2.728241 1.62023,-4.187421 -0.0728,-1.45918 -1.17167,-3.327723 -2.98326,-4.656218 l -0.0943,0.128122 c 0.9573,0.70201 1.46819,1.436147 1.74901,2.182965 -1.79766,-0.55845 -3.60517,-1.247574 -5.49843,-2.393956 2.05511,-2.472308 5.04919,-4.457371 7.76909,-4.751431 z m -8.14817,5.231491 c 2.1205,1.315607 4.12788,2.060108 6.08789,2.657382 0.0804,0.40224 0.11629,0.806225 0.13641,1.209261 0.0155,0.310196 -0.009,0.620198 -0.064,0.928701 -2.34508,-0.699963 -4.71918,-1.669518 -7.15347,-3.097895 0.24443,-0.581191 0.58447,-1.150757 0.99319,-1.697449 z m -1.20681,2.281122 c 2.45766,1.447102 4.85546,2.433323 7.20995,3.146392 -0.21346,0.665159 -0.56894,1.317554 -1.01181,1.943437 -2.10444,-0.349993 -4.1907,-1.335746 -6.28141,-2.62392 -0.0568,-0.341235 -0.0846,-0.683509 -0.10167,-1.025024 -0.0241,-0.482414 0.044,-0.964658 0.18494,-1.440885 z"
+                 style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#e6e6e6;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.09914997;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+            </g>
+          </g>
+        </g>
+      </g>
+      <path
+         style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;stroke:none;stroke-width:2.45669293;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+         d="m 419.70646,445.27997 -6.62271,-3.82939 0.0567,-18.4318 0.0567,-18.43179 9.34391,-5.39791 c 5.13915,-2.96885 12.25004,-7.07313 15.80197,-9.12063 l 6.45806,-3.72272 6.77247,3.92096 6.77248,3.92096 -2.87647,0.93303 c -15.6428,5.07399 -27.43493,13.88463 -30.83572,23.03928 -1.79172,4.82314 -0.57286,10.03842 3.55075,15.19301 0.60382,0.75478 1.77799,1.9639 2.60926,2.68691 l 1.5114,1.31458 0.51941,-0.51942 0.51941,-0.51941 -1.61724,-1.61724 c -1.55382,-1.55382 -3.00942,-3.85682 -3.34746,-5.29626 -0.15776,-0.67176 -0.11579,-0.65829 2.3038,0.73957 4.62057,2.66942 9.75041,4.88913 14.42669,6.24248 l 2.87083,0.83085 -2.0513,1.48643 c -4.91331,3.5603 -11.21656,7.0862 -16.61773,9.2956 -1.55422,0.63576 -2.8611,1.14611 -2.90419,1.13411 -0.0431,-0.012 -3.05857,-1.74504 -6.70106,-3.8512 z"
+         id="path5267"
+         inkscape:connector-curvature="0"
+         transform="scale(0.26458333)" />
+    </g>
+    <path
+       style="opacity:1;vector-effect:none;fill:#2c89a0;fill-opacity:1;stroke:none;stroke-width:0.1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+       d="m 113.08257,85.919016 -1.82271,-1.052935 -5.3e-4,-4.862677 -5.3e-4,-4.862676 4.21775,-2.435168 4.21774,-2.435167 1.85887,1.071867 c 1.02237,0.589527 1.8591,1.076281 1.8594,1.081675 2.7e-4,0.0054 -0.0609,0.02653 -0.13589,0.04698 -0.075,0.02044 -0.33734,0.09936 -0.58291,0.175368 -2.14471,0.663846 -3.9908,1.554716 -5.38256,2.597472 -1.86302,1.395853 -2.97678,2.958732 -3.10998,4.364098 -0.04,0.422056 0.029,0.935875 0.1906,1.418734 0.25164,0.752031 0.69363,1.441052 1.33934,2.087874 0.26247,0.26293 0.61231,0.571215 0.66089,0.582399 0.0215,0.0049 0.22456,-0.157144 0.22456,-0.179239 0,-0.0066 -0.054,-0.05542 -0.11989,-0.108407 -0.41571,-0.334043 -0.79884,-0.788239 -0.99597,-1.180696 -0.12177,-0.242452 -0.26654,-0.673634 -0.23631,-0.703864 0.006,-0.0055 0.12785,0.06017 0.27183,0.145983 1.61506,0.962591 3.21926,1.649095 4.74031,2.028578 l 0.31133,0.07767 -0.22865,0.173752 c -1.26642,0.962359 -2.88036,1.919568 -4.33602,2.571645 -0.45536,0.203983 -1.0649,0.453442 -1.10161,0.450839 -0.009,-6.45e-4 -0.83676,-0.474993 -1.83925,-1.054107 z"
+       id="path1073"
+       inkscape:connector-curvature="0" />
+    <g
+       id="g834"
+       transform="matrix(1.3323242,0,0,1.3323242,1.3174542,-50.39858)"
+       style="stroke-width:0.75056803">
+      <g
+         aria-label="SHEFFIELD"
+         style="font-style:normal;font-weight:normal;font-size:12.26865864px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#2ca05a;fill-opacity:1;stroke:none;stroke-width:0.19858779"
+         id="text829">
+        <path
+           d="m 101.34126,103.29875 c 0,-1.51694 -2.173109,-1.23472 -2.173109,-2.20838 0,-0.43039 0.366889,-0.71967 0.783167,-0.71967 0.395112,0 0.613832,0.1905 0.804332,0.51505 l 0.41628,-0.27516 c -0.26811,-0.46567 -0.67028,-0.73378 -1.213556,-0.73378 -0.705556,0 -1.319389,0.47978 -1.319389,1.21356 0,1.38288 2.173115,1.12183 2.173115,2.22955 0,0.52917 -0.42334,0.93133 -0.945449,0.93133 -0.536222,0 -0.860777,-0.35983 -0.959555,-0.86077 l -0.508,0.14111 c 0.169333,0.73378 0.684389,1.21355 1.453444,1.21355 0.81844,0 1.48872,-0.61383 1.48872,-1.44639 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2ca05a;fill-opacity:1;stroke-width:0.19858779"
+           id="path850" />
+        <path
+           d="m 105.76508,104.66048 v -4.706059 h -0.52916 v 1.919109 h -2.40595 v -1.919109 h -0.52211 v 4.706059 h 0.52211 v -2.30011 h 2.40595 v 2.30011 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2ca05a;fill-opacity:1;stroke-width:0.19858779"
+           id="path852" />
+        <path
+           d="m 109.41985,104.66048 v -0.48684 h -1.91206 v -1.8415 h 1.86267 v -0.48683 h -1.86267 v -1.397 h 1.91206 v -0.493889 h -2.43417 v 4.706059 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2ca05a;fill-opacity:1;stroke-width:0.19858779"
+           id="path854" />
+        <path
+           d="m 112.52428,100.44831 v -0.493889 h -2.13783 v 4.706059 h 0.52211 v -2.32834 h 1.56633 v -0.48683 h -1.56633 v -1.397 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2ca05a;fill-opacity:1;stroke-width:0.19858779"
+           id="path856" />
+        <path
+           d="m 115.57933,100.44831 v -0.493889 h -2.13784 v 4.706059 h 0.52212 v -2.32834 h 1.56633 v -0.48683 h -1.56633 v -1.397 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2ca05a;fill-opacity:1;stroke-width:0.19858779"
+           id="path858" />
+        <path
+           d="m 117.01865,104.66048 v -4.706059 h -0.52211 v 4.706059 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2ca05a;fill-opacity:1;stroke-width:0.19858779"
+           id="path860" />
+        <path
+           d="m 120.68048,104.66048 v -0.48684 h -1.91205 v -1.8415 h 1.86266 v -0.48683 h -1.86266 v -1.397 h 1.91205 v -0.493889 h -2.43417 v 4.706059 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2ca05a;fill-opacity:1;stroke-width:0.19858779"
+           id="path862" />
+        <path
+           d="m 123.46741,104.66048 v -0.48684 h -1.29822 v -4.219219 h -0.52211 v 4.706059 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2ca05a;fill-opacity:1;stroke-width:0.19858779"
+           id="path864" />
+        <path
+           d="m 127.67252,102.31098 c 0,-0.70556 -0.26105,-1.34761 -0.80433,-1.80623 -0.51506,-0.43038 -1.0795,-0.550329 -1.73567,-0.550329 h -0.95955 v 4.706059 h 0.9525 c 0.66322,0 1.19944,-0.10584 1.72155,-0.54328 0.55739,-0.46567 0.8255,-1.08656 0.8255,-1.80622 z m -0.52916,0 c 0,0.55033 -0.21873,1.07244 -0.64206,1.43227 -0.38806,0.33162 -0.84667,0.43039 -1.34761,0.43039 h -0.45861 v -3.72533 h 0.45861 c 1.143,0 1.98967,0.67733 1.98967,1.86267 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2ca05a;fill-opacity:1;stroke-width:0.19858779"
+           id="path866" />
+      </g>
+      <g
+         aria-label="LAB"
+         style="font-style:normal;font-weight:normal;font-size:7.05555534px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#2c89a0;fill-opacity:1;stroke:none;stroke-width:0.19858779"
+         id="text849">
+        <path
+           d="m 132.34681,104.74514 v -0.48683 h -1.29822 v -4.21923 h -0.52211 v 4.70606 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2c89a0;fill-opacity:1;stroke-width:0.19858779"
+           id="path869" />
+        <path
+           d="m 137.0458,104.74514 -2.10961,-4.931833 -2.16606,4.931833 h 0.5715 l 0.56445,-1.3335 h 2.01083 l 0.55034,1.3335 z m -1.3335,-1.82033 h -1.59455 l 0.80433,-1.88384 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2c89a0;fill-opacity:1;stroke-width:0.19858779"
+           id="path871" />
+        <path
+           d="m 140.48185,103.4187 c 0,-0.57856 -0.33161,-1.03012 -0.889,-1.18534 0.31044,-0.22578 0.46567,-0.53622 0.46567,-0.91722 0,-0.36689 -0.14817,-0.74083 -0.43745,-0.98072 -0.29633,-0.24695 -0.69144,-0.29634 -1.06539,-0.29634 h -0.84666 v 4.70606 h 1.17122 c 0.42333,0 0.79022,-0.0494 1.12889,-0.32456 0.30339,-0.24694 0.47272,-0.60677 0.47272,-1.00188 z m -0.93839,-2.0955 c 0,0.22577 -0.0705,0.46566 -0.24694,0.61383 -0.19756,0.16933 -0.43039,0.17639 -0.67028,0.17639 h -0.39511 v -1.58045 h 0.40922 c 0.53622,0 0.90311,0.20461 0.90311,0.79023 z m 0.41628,2.08138 c 0,0.24695 -0.10583,0.49389 -0.30339,0.64912 -0.22578,0.18344 -0.48683,0.20461 -0.76906,0.20461 h -0.65616 v -1.69334 h 0.53622 c 0.26106,0 0.56444,0.007 0.79728,0.14111 0.24694,0.14112 0.39511,0.41628 0.39511,0.6985 z"
+           style="font-style:normal;font-variant:normal;font-weight:500;font-stretch:normal;font-size:7.05555534px;font-family:'FuturaEF Book';-inkscape-font-specification:'FuturaEF Book, Medium';fill:#2c89a0;fill-opacity:1;stroke-width:0.19858779"
+           id="path873" />
+      </g>
+    </g>
+  </g>
+</svg>
diff --git a/seqcolapi/static/seqcol_list.html b/seqcolapi/static/seqcol_list.html
new file mode 100644
index 0000000..8a71e8f
--- /dev/null
+++ b/seqcolapi/static/seqcol_list.html
@@ -0,0 +1,454 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+  	
+    <!-- Required meta tags -->
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Sequence Collections API</title>
+  	
+  </head>
+  <body>
+		
+		<nav class="navbar navbar-expand-md py-2 mb-4 border-bottom navbar-light" aria-label="navbar" style="background-color: #EFF3F6;">
+		  <div class="container">
+		    <a href="/" class="align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
+		      <img src="/seqcol_logo.svg" alt="Sequence Collections" height="40"> Sequence collections
+		    </a>
+		    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+		      <span class="navbar-toggler-icon"></span>
+		    </button>
+		    <div class="collapse navbar-collapse me-auto" id="navbarSupportedContent">
+		      <ul class="navbar-nav ms-auto mb-2 mb-sm-0">        
+		      <li class="nav-item mx-2 my-0 h5">
+		        <a class="nav-link" href="/docs">API docs</a>
+		      </li>
+		      <li class="nav-item mx-2 my-0 h5">
+		      <a class="nav-link" href="https://github.com/refgenie/seqcol" target="_blank"><i class="fa fa-2x fa-github" aria-hidden="true"></i>GitHub</a>
+		      <li>
+		      </ul>
+		    </div>
+		  </div>
+		</nav>
+    
+    <div class="container">
+    
+<h3>Sequence collection list</h3>
+
+<table class="table mt-5">
+<thead>
+  <th>Assembly</th>
+  <th>Sequence collection digest</th>
+</thead><tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_009914755.4">T2T-CHM13v2.0</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/cT0L9BSX-_X5Wv_lbpJRXAFOEPj0Dvav">cT0L9BSX-_X5Wv_lbpJRXAFOEPj0Dvav</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018466835.1">HG02257.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/MFxJDHkVdTBlPvUFRbYWDZYxmycvHSRp">MFxJDHkVdTBlPvUFRbYWDZYxmycvHSRp</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018466845.1">HG02257.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/PU_Crd5eY96THL1Jkf1oJ0ABf3hcQfPv">PU_Crd5eY96THL1Jkf1oJ0ABf3hcQfPv</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018466855.1">HG02559.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/OCV0NxSbsWc-Xh3nPSQ0GrnAmYpRGFAL">OCV0NxSbsWc-Xh3nPSQ0GrnAmYpRGFAL</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018466985.1">HG02559.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/-UZ3ln8PXKtOgREFMkdncoMzTSV-Eaj5">-UZ3ln8PXKtOgREFMkdncoMzTSV-Eaj5</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018467005.1">HG02486.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/8Qlx8ZKwKL4U5s100-rjUZCA7UcWxpJr">8Qlx8ZKwKL4U5s100-rjUZCA7UcWxpJr</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018467015.1">HG02486.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/ZXK7B5SQ2iX_esmgYtwaOBtgTr3dwd7L">ZXK7B5SQ2iX_esmgYtwaOBtgTr3dwd7L</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018467155.1">HG01891.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/vUoInwW05o32k_Cq6-xkenrzLWF9oZ4N">vUoInwW05o32k_Cq6-xkenrzLWF9oZ4N</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018467165.1">HG01891.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/Zu_hdPQWU5DTGGRPa3cf_0TVNjdspvj-">Zu_hdPQWU5DTGGRPa3cf_0TVNjdspvj-</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469405.1">HG01258.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/cH3KUtgjMAxCl6Tkn5aCPPl_Yqyo-mkl">cH3KUtgjMAxCl6Tkn5aCPPl_Yqyo-mkl</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469415.1">HG03516.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/mSSLkiEl3Y7Bub48I1Ng-iVLCZm3_wli">mSSLkiEl3Y7Bub48I1Ng-iVLCZm3_wli</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469425.1">HG03516.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/S3kEaQ_QvrAYuZs2R8Un6hg3f_1ibteZ">S3kEaQ_QvrAYuZs2R8Un6hg3f_1ibteZ</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469665.1">HG01123.pri.mat.f1_v2.1</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/Ld18iSJB2oh7kTRGpFJD5bupqnHaXt-r">Ld18iSJB2oh7kTRGpFJD5bupqnHaXt-r</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469675.1">HG01258.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/SQuRKoVbeO2JdcGRSO_WxmZsmAxbqSdb">SQuRKoVbeO2JdcGRSO_WxmZsmAxbqSdb</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469685.1">HG01361.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/uc3BXswbHLIuPEuBa-pY7MAT8qNNFHhY">uc3BXswbHLIuPEuBa-pY7MAT8qNNFHhY</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469695.1">HG01123.alt.pat.f1_v2.1</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/RfpuPSsslqdCmPGat5yqoQF10qZXA2OJ">RfpuPSsslqdCmPGat5yqoQF10qZXA2OJ</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469705.1">HG01361.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/4YXbbLQwvkukFrZDm-NUQpZggJ81HeoO">4YXbbLQwvkukFrZDm-NUQpZggJ81HeoO</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469865.1">HG01358.pri.mat.f1_v2.1</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/CxRryMc8SwVpuan6rL3Nw5-qnTU1JYCo">CxRryMc8SwVpuan6rL3Nw5-qnTU1JYCo</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469875.1">HG02622.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/xCb3Ha1fm7Uz6dwvN5JXqdPLRVrMTTm9">xCb3Ha1fm7Uz6dwvN5JXqdPLRVrMTTm9</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469925.1">HG02622.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/s8IHAP13yprMBvOzZaOkDkCP6wks008y">s8IHAP13yprMBvOzZaOkDkCP6wks008y</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469935.1">HG02717.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/rQTvFXRJg1fktSlSFGfkf1tGN6jV57n8">rQTvFXRJg1fktSlSFGfkf1tGN6jV57n8</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469945.1">HG02630.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/G45RS0KtkiRThy4lp_tzRzoTNe__YZ6M">G45RS0KtkiRThy4lp_tzRzoTNe__YZ6M</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469955.1">HG02630.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/JiBQCxx8g1OqKfuQdxW5H4-XNIsJ_E1B">JiBQCxx8g1OqKfuQdxW5H4-XNIsJ_E1B</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018469965.1">HG01358.alt.pat.f1_v2.1</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/f4NOc-aMUFU2JCm5tGQYAsBnzS9iTXwW">f4NOc-aMUFU2JCm5tGQYAsBnzS9iTXwW</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018470425.1">HG02717.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/TppX7IsQ-f5TlUcLhqklj-Ya9KlytKIB">TppX7IsQ-f5TlUcLhqklj-Ya9KlytKIB</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018470435.1">HG02572.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/UIshAuHmM4BsVnAxjJEs3D7ZJV7Tx9uK">UIshAuHmM4BsVnAxjJEs3D7ZJV7Tx9uK</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018470445.1">HG02572.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/-xS7eWQFw9s3HxA-TQsHKtU-2qCc9J--">-xS7eWQFw9s3HxA-TQsHKtU-2qCc9J--</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018470455.1">HG02886.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/5goiErAN_XrYjB-6MT9Og4QXZ0gsHca7">5goiErAN_XrYjB-6MT9Og4QXZ0gsHca7</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018470465.1">HG02886.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/vTYYcCahSkIu5PME4JyLstVt7eOXekXD">vTYYcCahSkIu5PME4JyLstVt7eOXekXD</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471065.1">HG01175.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/zhDl_7kiYDY49LpM5_g3SJ99gkAn3hGj">zhDl_7kiYDY49LpM5_g3SJ99gkAn3hGj</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471075.1">HG01106.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/b2veuoCX_cwS1bHf0E133npWU66K5X5Y">b2veuoCX_cwS1bHf0E133npWU66K5X5Y</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471085.1">HG01175.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/L2qjWuBkmwM1eDgVDCFuOjyqleUZ7X4U">L2qjWuBkmwM1eDgVDCFuOjyqleUZ7X4U</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471095.1">HG00741.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/sPeVwLWKqdHlatwcYf7u-OmcBJNmG_32">sPeVwLWKqdHlatwcYf7u-OmcBJNmG_32</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471105.1">HG00741.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/xZ0Xf-pTJSKc0oGUDV3zL3_TcpO5nl1d">xZ0Xf-pTJSKc0oGUDV3zL3_TcpO5nl1d</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471345.1">HG01106.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/73AP6Fn5d7P7RB04axUk-24ssrnJb4Ab">73AP6Fn5d7P7RB04axUk-24ssrnJb4Ab</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471515.1">HG00438.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/-9M0kYfdvscDEVL13kKp87c8NCU2B5Hh">-9M0kYfdvscDEVL13kKp87c8NCU2B5Hh</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471525.1">HG02148.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/mmZHq6GxnHALdsbider2E5Jp-AhVxWVt">mmZHq6GxnHALdsbider2E5Jp-AhVxWVt</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471535.1">HG02148.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/cq2ryytoR7YEu8UUHtRnNr5KDA4NErUQ">cq2ryytoR7YEu8UUHtRnNr5KDA4NErUQ</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471545.1">HG01952.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/jcQVpDWreZwQAVQicTW4dNPQ8Fz3eYjh">jcQVpDWreZwQAVQicTW4dNPQ8Fz3eYjh</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018471555.1">HG01952.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/5Pum9BofAqDuL43GMQ6EqLwQVFQsTTSZ">5Pum9BofAqDuL43GMQ6EqLwQVFQsTTSZ</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472565.1">HG00673.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/fMW6DR6vGda_MfSmeScSip0XPmauTcLO">fMW6DR6vGda_MfSmeScSip0XPmauTcLO</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472575.1">HG00621.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/7Z-1F3kSi-eXduHZIG5R3rZAGvJ5Depi">7Z-1F3kSi-eXduHZIG5R3rZAGvJ5Depi</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472585.1">HG00673.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/4HylbyjZIYZP7XlgQ3N8jw4xJ8pgl7bb">4HylbyjZIYZP7XlgQ3N8jw4xJ8pgl7bb</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472595.1">HG00438.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/Garq3gUkWDFi6vkyYkdQn_p5tUVu3_hm">Garq3gUkWDFi6vkyYkdQn_p5tUVu3_hm</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472605.1">HG00621.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/BjbE7ZEeWbNVZeYqeyBXYScwlBVimZBB">BjbE7ZEeWbNVZeYqeyBXYScwlBVimZBB</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472685.1">HG01071.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/x0CrFmo9JcS1QVIm1GY4XWjpl9p8WHRl">x0CrFmo9JcS1QVIm1GY4XWjpl9p8WHRl</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472695.1">HG01928.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/p2xs5S6BOA1LiQKMSMJ3snTQVIF0NtjW">p2xs5S6BOA1LiQKMSMJ3snTQVIF0NtjW</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472705.1">HG01928.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/emHHDrJgEwvhf03dJP-Pk8vXHK_KHeOr">emHHDrJgEwvhf03dJP-Pk8vXHK_KHeOr</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472715.1">HG00735.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/ny1PsG4UOLGUzECAX2ZTxRaYaQGLiZZi">ny1PsG4UOLGUzECAX2ZTxRaYaQGLiZZi</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472725.1">HG01071.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/soFuT59nkwqdZ3i9FZ6GsPaC8v0UqpZU">soFuT59nkwqdZ3i9FZ6GsPaC8v0UqpZU</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472765.1">HG00735.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/BbH1ZrRSfhBhVHhYLBYq8FNiaSeJHryC">BbH1ZrRSfhBhVHhYLBYq8FNiaSeJHryC</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472825.1">HG03579.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/Hmdch7xzoR_8uyaCHQwvmGWn40e4c58U">Hmdch7xzoR_8uyaCHQwvmGWn40e4c58U</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472835.1">HG03579.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/cYrHK5KVoZeyjdS3Mo1srvDYoP44DtWn">cYrHK5KVoZeyjdS3Mo1srvDYoP44DtWn</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472845.1">HG01978.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/FBe70obDKdaLQbFC6rigZBlrkjjhOJ6o">FBe70obDKdaLQbFC6rigZBlrkjjhOJ6o</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472855.1">HG03453.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/LXAPWhSKfrwQkCZsoGPy1W3XSGwwZJR1">LXAPWhSKfrwQkCZsoGPy1W3XSGwwZJR1</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018472865.1">HG01978.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/r6ieZ0QGT0NLHuqtkpQQyCXiXXRBwExd">r6ieZ0QGT0NLHuqtkpQQyCXiXXRBwExd</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018473295.1">HG03540.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/Kc-Q1c-dlAmYoTS9a5C-wnXXNTJZEL7Y">Kc-Q1c-dlAmYoTS9a5C-wnXXNTJZEL7Y</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018473305.1">HG03453.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/P0njMo_ngJB7KvnLAPjBPnGXoigeXAVA">P0njMo_ngJB7KvnLAPjBPnGXoigeXAVA</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018473315.1">HG03540.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/y7kmkFlydCwj48nHNFJ76TMzNjfYPFno">y7kmkFlydCwj48nHNFJ76TMzNjfYPFno</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018503245.1">HG03486.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/yK-YzwV_nIfvoov5f5yCfX2WK18booij">yK-YzwV_nIfvoov5f5yCfX2WK18booij</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018503255.1">NA18906.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/JLxVTGB1J1NsHwQc9Ph1G1uvJoF0vcmX">JLxVTGB1J1NsHwQc9Ph1G1uvJoF0vcmX</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018503265.1">NA19240.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/EsxyPLersYlRzzZ-ccHQ5mJK0_sU2eUn">EsxyPLersYlRzzZ-ccHQ5mJK0_sU2eUn</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018503275.1">NA19240.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/rMLfj_2guPmN7lVgtRCiSS2_baCN1whg">rMLfj_2guPmN7lVgtRCiSS2_baCN1whg</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018503285.1">NA18906.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/BqfaoAPziDGbqTeaTlLzQD_cf6frizzK">BqfaoAPziDGbqTeaTlLzQD_cf6frizzK</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018503525.1">HG03486.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/BuZj05B1DuUyRND9eYKf4LhrOMDBtyOk">BuZj05B1DuUyRND9eYKf4LhrOMDBtyOk</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018503575.1">HG02818.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/WtvqOdQqFvqVdAzs8ql5-d8vwwtEOXUD">WtvqOdQqFvqVdAzs8ql5-d8vwwtEOXUD</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018503585.1">HG02818.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/iB8zea9dHlENH43vvkCtcxZlJ4wT1Uz1">iB8zea9dHlENH43vvkCtcxZlJ4wT1Uz1</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504045.1">HG01243.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/yFCTQeIXhkSUukadRWjWvOVRsz_OyTGq">yFCTQeIXhkSUukadRWjWvOVRsz_OyTGq</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504055.1">HG02080.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/tt6XTgH0zmAtOqbVHzM28MomIrnW4SuA">tt6XTgH0zmAtOqbVHzM28MomIrnW4SuA</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504065.1">HG02723.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/NcoX-bKBNYbA2o6EwJeQk1IH8ZtZZgps">NcoX-bKBNYbA2o6EwJeQk1IH8ZtZZgps</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504075.1">HG02723.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/Vdn0RtSTthV_5EImofY-lSeO3a3bwIQX">Vdn0RtSTthV_5EImofY-lSeO3a3bwIQX</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504085.1">HG02080.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/XVWtB0SreQEBLIfzbOjbKG5PEb1asj6k">XVWtB0SreQEBLIfzbOjbKG5PEb1asj6k</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504365.1">HG01109.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/PhKsGQm9pHaNLkimAYQPsornvIZpqvnH">PhKsGQm9pHaNLkimAYQPsornvIZpqvnH</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504375.1">HG01243.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/03eDIlAb6h7tiYvcU2f43-A-RmJzN632">03eDIlAb6h7tiYvcU2f43-A-RmJzN632</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504625.1">NA20129.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/tzg-YjJ70yBfIo5ijfN3LgsPAfc2fH-y">tzg-YjJ70yBfIo5ijfN3LgsPAfc2fH-y</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504635.1">NA20129.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/eYQOqMmclnUP_SYW5KnMCKcfCOtY2Jfn">eYQOqMmclnUP_SYW5KnMCKcfCOtY2Jfn</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504645.1">HG01109.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/t2DLI454ZtI0hxz3ublokln-RrQtZfLO">t2DLI454ZtI0hxz3ublokln-RrQtZfLO</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504655.1">NA21309.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/tJW0O7A3G4KGYoJ9OGwA0G2hLRm9MHQC">tJW0O7A3G4KGYoJ9OGwA0G2hLRm9MHQC</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018504665.1">NA21309.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/Sz7UMHSkMT6X29fRukTjWiKb2NPjkfpz">Sz7UMHSkMT6X29fRukTjWiKb2NPjkfpz</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018505825.1">HG02109.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/kfe4S1NWXJrzdkn7-PEmO14qQ_97iPcT">kfe4S1NWXJrzdkn7-PEmO14qQ_97iPcT</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018505835.1">HG03492.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/Lt9FTvjBEThMyHAm-_st-2ygIlqTUcSK">Lt9FTvjBEThMyHAm-_st-2ygIlqTUcSK</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018505845.1">HG03492.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/SXDV7XYbyfGfknp07q5u4Foz6P7j19pn">SXDV7XYbyfGfknp07q5u4Foz6P7j19pn</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018505855.1">HG02055.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/av3aqrEvSnd3t2EM0m6jXTtjC0ap8hGm">av3aqrEvSnd3t2EM0m6jXTtjC0ap8hGm</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018505865.1">HG02109.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/fEQuZ-F9oVaqzhXzl-6Ziq4Zj8XUpXQf">fEQuZ-F9oVaqzhXzl-6Ziq4Zj8XUpXQf</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018506125.1">HG02055.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/j1V8g5DkGVx7R_5W7y8M_yxMUwqgOXeF">j1V8g5DkGVx7R_5W7y8M_yxMUwqgOXeF</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018506155.1">HG03098.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/0PSK6PxA62LbmS0DRQb2VeH2UW2byEOl">0PSK6PxA62LbmS0DRQb2VeH2UW2byEOl</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018506165.1">HG03098.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/tX5MdWuQMBqkg7lEbdozJNyseAKOdRqi">tX5MdWuQMBqkg7lEbdozJNyseAKOdRqi</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018506945.1">HG005.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/MC8U95jiJqlpU7FkwtTWBILApRLW11tv">MC8U95jiJqlpU7FkwtTWBILApRLW11tv</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018506955.1">HG00733.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/OdOkD0fYg_ryMFWq5fgNjxR4DxsdgAMo">OdOkD0fYg_ryMFWq5fgNjxR4DxsdgAMo</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018506965.1">HG005.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/HhM9RLhBL4ggspYnU7_MI_QrLQZoUTqJ">HhM9RLhBL4ggspYnU7_MI_QrLQZoUTqJ</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018506975.1">HG00733.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/tFKFtJwX3jVBaQcYgyLEOOt82rlJqou8">tFKFtJwX3jVBaQcYgyLEOOt82rlJqou8</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018852585.1">HG02145.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/VgBPdkMRNxWi6UR2VXQDrYNJYtNn0Uf4">VgBPdkMRNxWi6UR2VXQDrYNJYtNn0Uf4</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018852595.1">HG02145.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/f0oF1fypWOJulxmykodrzqek3LEVHtTv">f0oF1fypWOJulxmykodrzqek3LEVHtTv</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018852605.1">HG002.alt.pat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/rnrRAhWZmbGjP1CK-L9I1eHNfKJNqkoH">rnrRAhWZmbGjP1CK-L9I1eHNfKJNqkoH</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_018852615.1">HG002.pri.mat.f1_v2</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/tQLJhZVyD-ehl1lkqTMv-sieRJcejmvk">tQLJhZVyD-ehl1lkqTMv-sieRJcejmvk</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_021950905.1">HG002.pat.cur.20211005</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/6BCEz05tbMxTTl6k4x9gFmgkNaXECShd">6BCEz05tbMxTTl6k4x9gFmgkNaXECShd</a></th>
+</tr>
+<tr>
+  <th><a href="https://www.ebi.ac.uk/ena/browser/view/GCA_021951015.1">HG002.mat.cur.20211005</a></th>
+  <th><a href="http://seqcolapi.databio.org/collection/XjCjW7CHIqVb6lTzxhAVL-vaMohzgXAt">XjCjW7CHIqVb6lTzxhAVL-vaMohzgXAt</a></th>
+</tr>
+
+
+</table>
+
+	</div>
+		
+		<div class="container">
+		  <footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top align-top">
+		  <span class="badge rounded-pill bg-secondary">seqcolapi </span>
+		  <span class="badge rounded-pill bg-secondary">seqcol </span>
+		  <span class="badge rounded-pill bg-secondary">
+		    Python </span>
+
+		  <div class="ms-auto">
+		    <a href="https://databio.org/"><img src="static/logo_databio_long.svg" alt="Sheffield Computational Biology Lab" width="200"></a>
+		  </div>
+			</footer>
+		</div>
+		
+  </body>	
+  	<!-- Bootstrap CSS -->
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
+    <!-- Custom CSS -->
+    <link rel="stylesheet" href="https://databio.org/css/databio.css">
+</html>
\ No newline at end of file
diff --git a/seqcolapi/static/seqcol_logo.svg b/seqcolapi/static/seqcol_logo.svg
new file mode 100644
index 0000000..44202df
--- /dev/null
+++ b/seqcolapi/static/seqcol_logo.svg
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   width="96"
+   height="96"
+   viewBox="0 0 25.400001 25.4"
+   version="1.1"
+   id="svg5"
+   inkscape:version="1.3 (1:1.3+202307231459+0e150ed6c4)"
+   sodipodi:docname="seqcol_logo.svg"
+   xml:space="preserve"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
+     id="namedview7"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0"
+     inkscape:pagecheckerboard="0"
+     inkscape:document-units="mm"
+     showgrid="false"
+     inkscape:zoom="2.4699654"
+     inkscape:cx="180.16447"
+     inkscape:cy="79.55577"
+     inkscape:window-width="2488"
+     inkscape:window-height="1343"
+     inkscape:window-x="1272"
+     inkscape:window-y="27"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer1"
+     inkscape:snap-global="false"
+     inkscape:showpageshadow="2"
+     inkscape:deskcolor="#eeeeee"><inkscape:page
+       x="0"
+       y="0"
+       width="25.400002"
+       height="25.4"
+       id="page4"
+       margin="4"
+       bleed="0"
+       inkscape:export-filename="seqcol_logo.png"
+       inkscape:export-xdpi="64"
+       inkscape:export-ydpi="64" /></sodipodi:namedview><defs
+     id="defs2" /><g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(-7.1425564,-2.3515459)"><g
+       id="g1768"
+       transform="matrix(1.7949691,0,0,1.7949691,-27.135218,-11.341666)" /><g
+       id="g1"><g
+         id="g4"
+         transform="translate(-5.8775965,-5.1242765)"><path
+           style="color:#000000;text-indent:0;text-transform:none;direction:ltr;baseline-shift:baseline;fill:#3333cc;fill-opacity:1;stroke-width:0.166773;enable-background:accumulate"
+           d="M 32.906397,8.8365113 A 0.33357198,0.33358032 0 0 0 32.572858,8.5342326 c -1.031268,0.00252 -1.85482,0.5054766 -2.485906,1.2091084 -0.631084,0.703632 -1.09553,1.608382 -1.485287,2.491177 a 0.33357198,0.33358032 0 0 0 -0.0052,0.0104 c -0.26457,0.649733 -0.602863,1.302863 -1.026675,1.824085 V 10.16025 c 0.126048,0.194657 0.247395,0.418542 0.364812,0.677518 a 0.33357196,0.3335803 0 0 0 0.641019,-0.156352 0.33357196,0.3335803 0 0 0 -0.03127,-0.114657 C 28.27135,9.9646986 27.962998,9.4510215 27.512433,9.0866432 27.061867,8.7222712 26.475257,8.5315916 25.735289,8.5342074 c -1.022705,0.00378 -1.838644,0.4688421 -2.449419,1.1152972 -0.608072,0.6436004 -1.033395,1.4635714 -1.355001,2.2514454 -0.0016,0.0038 -0.0037,0.0069 -0.0052,0.0104 -0.376909,0.852395 -0.819192,1.694521 -1.365425,2.303554 -0.05215,0.05818 -0.107736,0.113282 -0.161553,0.166778 V 9.7589227 c 0.200677,0.2076795 0.371636,0.4907213 0.521149,0.8911983 a 0.33357196,0.3335803 0 1 0 0.625401,-0.229312 C 21.29236,9.7433852 20.94327,9.245441 20.440415,8.9406914 19.937576,8.6359419 19.318663,8.5322471 18.564263,8.5341822 A 0.33357196,0.3335803 0 0 0 18.230716,8.8677313 V 15.53867 a 0.33357196,0.3335803 0 0 0 0.33875,0.333549 c 1.031294,-0.0025 1.854821,-0.505477 2.485909,-1.209109 0.631088,-0.703632 1.095535,-1.608381 1.485285,-2.491183 a 0.33357196,0.3335803 0 0 0 0.0052,-0.0104 c 0.26457,-0.649727 0.59765,-1.302857 1.021455,-1.824085 v 3.908759 c -0.126048,-0.194664 -0.242172,-0.418542 -0.359597,-0.677518 a 0.33363406,0.33364239 0 0 0 -0.60974,0.271002 c 0.272957,0.602061 0.581322,1.115745 1.031877,1.480117 0.450555,0.364378 1.037181,0.555051 1.777138,0.552436 1.02271,-0.0038 1.838656,-0.468843 2.449432,-1.115298 0.60808,-0.643599 1.033389,-1.46357 1.355002,-2.251439 0.0015,-0.0038 0.0037,-0.0069 0.0052,-0.0104 0.376929,-0.852395 0.819183,-1.694522 1.365422,-2.303554 0.05191,-0.05786 0.102766,-0.113604 0.156347,-0.166778 v 4.622753 C 30.536172,14.439849 30.366761,14.156808 30.21724,13.756331 a 0.33357198,0.33358032 0 1 0 -0.625383,0.229312 c 0.25292,0.677423 0.60721,1.175367 1.110057,1.480117 0.502849,0.304749 1.121764,0.408444 1.876155,0.406509 A 0.33357198,0.33358032 0 0 0 32.906397,15.53872 V 8.8677817 a 0.33357198,0.33358032 0 0 0 0,-0.031264 z m -0.667078,0.4065093 v 5.9360924 c -0.318387,-0.01853 -0.599989,-0.06007 -0.833845,-0.130288 V 9.5348736 a 0.33357198,0.33358032 0 0 0 0,-0.015632 c 0.25501,-0.1390497 0.533181,-0.2338884 0.833845,-0.276221 z M 26.902701,9.4723328 V 14.70485 a 0.33357198,0.33358032 0 0 0 0,0.005 c -0.295723,0.215886 -0.624599,0.369541 -1.000611,0.442992 V 9.2063483 c 0.426698,0.017397 0.74079,0.1074389 1.000611,0.2657954 z M 25.235013,9.2534461 v 5.9465179 c -0.428258,-0.01765 -0.740275,-0.111283 -1.000625,-0.271008 V 9.701645 a 0.33357198,0.33358032 0 0 0 0,-0.00504 c 0.29479,-0.2151992 0.626085,-0.369257 1.000625,-0.4429861 z m -5.503392,0.1042306 v 5.5139513 a 0.33357198,0.33358032 0 0 0 0,0.02086 c -0.256147,0.140556 -0.531441,0.23438 -0.833851,0.276215 V 9.2274074 c 0.32149,0.018468 0.597933,0.059188 0.833851,0.1302882 z"
+           fill="#000000"
+           fill-opacity="1"
+           stroke="none"
+           marker="none"
+           visibility="visible"
+           display="inline"
+           overflow="visible"
+           id="path1" /><path
+           style="color:#000000;font-variation-settings:normal;text-indent:0;text-transform:none;direction:ltr;baseline-shift:baseline;opacity:1;vector-effect:none;fill:#6666cc;fill-opacity:1;stroke:none;stroke-width:0.166773;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
+           d="m 32.906397,17.091018 a 0.33357198,0.33358032 0 0 0 -0.333539,-0.302279 c -1.031268,0.0025 -1.85482,0.505476 -2.485906,1.209108 -0.631084,0.703632 -1.09553,1.608382 -1.485287,2.491177 a 0.33357198,0.33358032 0 0 0 -0.0052,0.0104 c -0.26457,0.649733 -0.602863,1.302863 -1.026675,1.824085 v -3.908752 c 0.126048,0.194657 0.247395,0.418542 0.364812,0.677517 a 0.33357196,0.3335803 0 0 0 0.641019,-0.156352 0.33357196,0.3335803 0 0 0 -0.03127,-0.114656 c -0.272969,-0.602061 -0.581321,-1.115738 -1.031886,-1.480117 -0.450566,-0.364372 -1.037176,-0.555051 -1.777144,-0.552435 -1.022705,0.0038 -1.838644,0.468842 -2.449419,1.115297 -0.608072,0.643599 -1.033395,1.46357 -1.355001,2.251445 -0.0016,0.0038 -0.0037,0.0069 -0.0052,0.0104 -0.376909,0.852395 -0.819192,1.694522 -1.365425,2.303555 -0.05215,0.05818 -0.107736,0.113282 -0.161553,0.166777 v -4.622759 c 0.200677,0.207679 0.371636,0.49072 0.521149,0.891197 a 0.33357196,0.3335803 0 1 0 0.625401,-0.229312 c -0.252913,-0.677423 -0.602003,-1.175367 -1.104858,-1.480116 -0.502839,-0.30475 -1.121752,-0.408445 -1.876152,-0.40651 a 0.33357196,0.3335803 0 0 0 -0.333547,0.33355 v 6.670937 a 0.33357196,0.3335803 0 0 0 0.33875,0.333549 c 1.031294,-0.0025 1.854821,-0.505476 2.485909,-1.209108 0.631088,-0.703632 1.095535,-1.608382 1.485285,-2.491183 a 0.33357196,0.3335803 0 0 0 0.0052,-0.0104 c 0.26457,-0.649726 0.59765,-1.302856 1.021455,-1.824085 v 3.908759 C 23.441267,22.306044 23.325143,22.082165 23.207718,21.82319 a 0.33363406,0.33364239 0 0 0 -0.60974,0.271002 c 0.272957,0.602061 0.581322,1.115744 1.031877,1.480116 0.450555,0.364379 1.037181,0.555052 1.777138,0.552436 1.02271,-0.0038 1.838656,-0.468842 2.449432,-1.115297 0.60808,-0.6436 1.033389,-1.463571 1.355002,-2.251439 0.0015,-0.0038 0.0037,-0.0069 0.0052,-0.0104 0.376929,-0.852395 0.819183,-1.694522 1.365422,-2.303555 0.05191,-0.05786 0.102766,-0.113603 0.156347,-0.166777 v 4.622753 C 30.536172,22.694355 30.366761,22.411314 30.21724,22.010837 a 0.33357198,0.33358032 0 1 0 -0.625383,0.229312 c 0.25292,0.677423 0.60721,1.175367 1.110057,1.480116 0.502849,0.30475 1.121764,0.408445 1.876155,0.40651 a 0.33357198,0.33358032 0 0 0 0.328328,-0.333549 v -6.670938 a 0.33357198,0.33358032 0 0 0 0,-0.03126 z m -0.667078,0.406509 v 5.936092 c -0.318387,-0.01853 -0.599989,-0.06007 -0.833845,-0.130288 V 17.78938 a 0.33357198,0.33358032 0 0 0 0,-0.01563 c 0.25501,-0.13905 0.533181,-0.233889 0.833845,-0.276221 z m -5.336618,0.229312 v 5.232517 a 0.33357198,0.33358032 0 0 0 0,0.005 c -0.295723,0.215886 -0.624599,0.36954 -1.000611,0.442992 v -5.946537 c 0.426698,0.0174 0.74079,0.107439 1.000611,0.265796 z m -1.667688,-0.218887 v 5.946518 c -0.428258,-0.01765 -0.740275,-0.111284 -1.000625,-0.271008 v -5.227311 a 0.33357198,0.33358032 0 0 0 0,-0.005 c 0.29479,-0.2152 0.626085,-0.369257 1.000625,-0.442986 z m -5.503392,0.104231 v 5.513951 a 0.33357198,0.33358032 0 0 0 0,0.02086 c -0.256147,0.140557 -0.531441,0.23438 -0.833851,0.276215 v -5.941298 c 0.32149,0.01847 0.597933,0.05919 0.833851,0.130288 z"
+           fill="#000000"
+           fill-opacity="1"
+           stroke="none"
+           marker="none"
+           visibility="visible"
+           display="inline"
+           overflow="visible"
+           id="path2" /><path
+           style="color:#000000;font-variation-settings:normal;text-indent:0;text-transform:none;direction:ltr;baseline-shift:baseline;opacity:1;vector-effect:none;fill:#9999cc;fill-opacity:1;stroke:none;stroke-width:0.166773;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
+           d="m 32.906397,25.231806 a 0.33357198,0.33358032 0 0 0 -0.333539,-0.302279 c -1.031268,0.0025 -1.85482,0.505476 -2.485906,1.209108 -0.631084,0.703632 -1.09553,1.608382 -1.485287,2.491177 a 0.33357198,0.33358032 0 0 0 -0.0052,0.0104 c -0.26457,0.649733 -0.602863,1.302863 -1.026675,1.824085 v -3.908752 c 0.126048,0.194657 0.247395,0.418542 0.364812,0.677517 a 0.33357196,0.3335803 0 0 0 0.641019,-0.156352 0.33357196,0.3335803 0 0 0 -0.03127,-0.114656 c -0.272969,-0.602061 -0.581321,-1.115738 -1.031886,-1.480117 -0.450566,-0.364372 -1.037176,-0.555051 -1.777144,-0.552435 -1.022705,0.0038 -1.838644,0.468842 -2.449419,1.115297 -0.608072,0.643599 -1.033395,1.46357 -1.355001,2.251445 -0.0016,0.0038 -0.0037,0.0069 -0.0052,0.0104 -0.376909,0.852395 -0.819192,1.694522 -1.365425,2.303555 -0.05215,0.05818 -0.107736,0.113282 -0.161553,0.166777 v -4.622759 c 0.200677,0.207679 0.371636,0.490721 0.521149,0.891198 a 0.33357196,0.3335803 0 1 0 0.625401,-0.229313 c -0.252913,-0.677423 -0.602003,-1.175367 -1.104858,-1.480116 -0.502839,-0.30475 -1.121752,-0.408445 -1.876152,-0.40651 a 0.33357196,0.3335803 0 0 0 -0.333547,0.33355 v 6.670937 a 0.33357196,0.3335803 0 0 0 0.33875,0.333549 c 1.031294,-0.0025 1.854821,-0.505476 2.485909,-1.209108 0.631088,-0.703632 1.095535,-1.608382 1.485285,-2.491183 a 0.33357196,0.3335803 0 0 0 0.0052,-0.0104 c 0.26457,-0.649726 0.59765,-1.302856 1.021455,-1.824085 v 3.908759 c -0.126048,-0.194663 -0.242172,-0.418542 -0.359597,-0.677517 a 0.33363406,0.33364239 0 0 0 -0.60974,0.271002 c 0.272957,0.602061 0.581322,1.115744 1.031877,1.480116 0.450555,0.364379 1.037181,0.555052 1.777138,0.552436 1.02271,-0.0038 1.838656,-0.468842 2.449432,-1.115297 0.60808,-0.6436 1.033389,-1.46357 1.355002,-2.251439 0.0015,-0.0038 0.0037,-0.0069 0.0052,-0.0104 0.376929,-0.852395 0.819183,-1.694522 1.365422,-2.303555 0.05191,-0.05786 0.102766,-0.113603 0.156347,-0.166777 v 4.622753 C 30.536172,30.835143 30.366761,30.552102 30.21724,30.151625 a 0.33357198,0.33358032 0 1 0 -0.625383,0.229312 c 0.25292,0.677423 0.60721,1.175367 1.110057,1.480116 0.502849,0.30475 1.121764,0.408445 1.876155,0.40651 a 0.33357198,0.33358032 0 0 0 0.328328,-0.333549 v -6.670938 a 0.33357198,0.33358032 0 0 0 0,-0.03126 z m -0.667078,0.406509 v 5.936092 c -0.318387,-0.01853 -0.599989,-0.06007 -0.833845,-0.130288 v -5.513951 a 0.33357198,0.33358032 0 0 0 0,-0.01563 c 0.25501,-0.13905 0.533181,-0.233889 0.833845,-0.276221 z m -5.336618,0.229312 v 5.232517 a 0.33357198,0.33358032 0 0 0 0,0.005 c -0.295723,0.215886 -0.624599,0.36954 -1.000611,0.442992 v -5.946537 c 0.426698,0.0174 0.74079,0.107439 1.000611,0.265796 z M 25.235013,25.64874 v 5.946518 c -0.428258,-0.01765 -0.740275,-0.111284 -1.000625,-0.271008 v -5.227311 a 0.33357198,0.33358032 0 0 0 0,-0.005 c 0.29479,-0.2152 0.626085,-0.369257 1.000625,-0.442986 z m -5.503392,0.104231 v 5.513951 a 0.33357198,0.33358032 0 0 0 0,0.02086 C 19.475474,31.428342 19.20018,31.522165 18.89777,31.564 v -5.941298 c 0.32149,0.01847 0.597933,0.05919 0.833851,0.130288 z"
+           fill="#000000"
+           fill-opacity="1"
+           stroke="none"
+           marker="none"
+           visibility="visible"
+           display="inline"
+           overflow="visible"
+           id="path3" /><path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 16.424075,29.860518 c -0.198729,0.0034 -0.398524,-0.07216 -0.538938,-0.214146 -0.195082,-0.194386 -0.294341,-0.461128 -0.363807,-0.722201 -0.118343,-0.46928 -0.146657,-0.955414 -0.161622,-1.437374 -0.0239,-1.033217 0.0414,-2.06554 0.06237,-3.098227 0.01358,-0.722075 0.01879,-1.447526 -0.07081,-2.165465 -0.05329,-0.394914 -0.131452,-0.794985 -0.315444,-1.152136 -0.121452,-0.235403 -0.309283,-0.449295 -0.561031,-0.546895 -0.123598,-0.04927 -0.257182,-0.07047 -0.389892,-0.07031 m 0,-0.0073 c 0.198728,0.0034 0.398525,-0.07216 0.538938,-0.214146 0.195083,-0.194386 0.294339,-0.461128 0.363807,-0.722199 0.118343,-0.469282 0.146657,-0.955416 0.161623,-1.437376 0.0239,-1.033216 -0.0414,-2.06554 -0.06237,-3.098226 -0.01358,-0.722076 -0.01879,-1.447526 0.07081,-2.165466 0.05329,-0.394914 0.131453,-0.794983 0.315444,-1.152136 0.121452,-0.235402 0.309283,-0.449293 0.561031,-0.546894 0.123598,-0.04927 0.257182,-0.07047 0.389892,-0.07031"
+           id="path5147"
+           inkscape:connector-curvature="0" /><path
+           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 34.722402,29.860518 c 0.198729,0.0034 0.398524,-0.07216 0.538938,-0.214146 0.195082,-0.194386 0.294341,-0.461128 0.363807,-0.722201 0.118343,-0.46928 0.146657,-0.955414 0.161622,-1.437374 0.0239,-1.033217 -0.0414,-2.06554 -0.06237,-3.098227 -0.01358,-0.722075 -0.01879,-1.447526 0.07081,-2.165465 0.05329,-0.394914 0.131452,-0.794985 0.315444,-1.152136 0.121452,-0.235403 0.309283,-0.449295 0.561031,-0.546895 0.123598,-0.04927 0.257182,-0.07047 0.389892,-0.07031 m 0,-0.0073 c -0.198728,0.0034 -0.398525,-0.07216 -0.538938,-0.214146 -0.195083,-0.194386 -0.294339,-0.461128 -0.363807,-0.722199 -0.118343,-0.469282 -0.146657,-0.955416 -0.161623,-1.437376 -0.0239,-1.033216 0.0414,-2.06554 0.06237,-3.098226 0.01358,-0.722076 0.01879,-1.447526 -0.07081,-2.165466 -0.05329,-0.394914 -0.131453,-0.794983 -0.315444,-1.152136 -0.121452,-0.235402 -0.309283,-0.449293 -0.561031,-0.546894 -0.123598,-0.04927 -0.257182,-0.07047 -0.389892,-0.07031"
+           id="path4"
+           inkscape:connector-curvature="0" /></g></g></g></svg>
diff --git a/seqcolapi/static/seqcol_logo_old.svg b/seqcolapi/static/seqcol_logo_old.svg
new file mode 100644
index 0000000..bcac5aa
--- /dev/null
+++ b/seqcolapi/static/seqcol_logo_old.svg
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   version="1.1"
+   x="0px"
+   y="0px"
+   viewBox="0 0 471.45847 98.467247"
+   enable-background="new 0 0 100 100"
+   xml:space="preserve"
+   id="svg54"
+   sodipodi:docname="seqcol_logo.svg"
+   inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"
+   width="471.45847"
+   height="98.467247"><metadata
+   id="metadata60"><rdf:RDF><cc:Work
+       rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+         rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+   id="defs58" /><sodipodi:namedview
+   pagecolor="#ffffff"
+   bordercolor="#666666"
+   borderopacity="1"
+   objecttolerance="10"
+   gridtolerance="10"
+   guidetolerance="10"
+   inkscape:pageopacity="0"
+   inkscape:pageshadow="2"
+   inkscape:window-width="2560"
+   inkscape:window-height="1370"
+   id="namedview56"
+   showgrid="false"
+   inkscape:zoom="0.834386"
+   inkscape:cx="-487.8031"
+   inkscape:cy="271.95653"
+   inkscape:window-x="3760"
+   inkscape:window-y="204"
+   inkscape:window-maximized="1"
+   inkscape:current-layer="svg54"
+   fit-margin-top="3"
+   fit-margin-left="2"
+   fit-margin-right="2"
+   fit-margin-bottom="3" />
+<g
+   transform="translate(132.20339,-449.15254)"
+   id="g5061"><g
+     id="text4572-3"
+     style="font-style:normal;font-weight:normal;font-size:106.47197723px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+     aria-label="seqcol"><path
+       inkscape:connector-curvature="0"
+       id="path4988"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Manjari;-inkscape-font-specification:Manjari;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 51.121582,470.80639 c -10.865549,0 -23.810628,4.83491 -23.810628,16.42829 0,10.39766 10.345666,12.94508 19.23566,13.98485 6.60251,0.77982 20.639343,0.31193 20.639343,7.5383 0,6.91444 -8.734029,9.20192 -15.856422,9.20192 -8.318124,0 -14.764669,-2.54742 -17.728,-8.26613 -0.571871,-1.14375 -2.079531,-2.07953 -3.379238,-2.07953 -2.079531,0 -3.743155,1.66362 -3.743155,3.74315 0,0.51988 0.155964,1.29971 0.415906,1.7676 4.159061,8.11017 13.620926,12.37321 24.434487,12.37321 11.489407,0 23.342733,-5.04286 23.342733,-16.74022 0,-10.81356 -10.449642,-13.10105 -19.911508,-14.08882 -6.342568,-0.67585 -19.963495,-0.62386 -19.963495,-7.43433 0,-6.49853 9.825783,-8.88999 16.272328,-8.88999 6.758475,0 12.113267,2.54743 14.608704,7.22637 0.571871,1.14374 2.079531,2.02754 3.327249,2.02754 2.079531,0 3.795144,-1.66362 3.795144,-3.74315 0,-0.51989 -0.207953,-1.3517 -0.467894,-1.81959 -3.691167,-6.91444 -11.957302,-11.22947 -21.211214,-11.22947 z" /><path
+       inkscape:connector-curvature="0"
+       id="path4990"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Manjari;-inkscape-font-specification:Manjari;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 113.03961,525.39407 c 7.85023,0 15.49251,-3.5352 20.48338,-9.66981 0.51988,-0.62386 0.93579,-1.7676 0.93579,-2.54743 0,-2.13152 -1.7676,-3.89912 -3.89912,-3.89912 -1.03977,0 -2.44345,0.67585 -3.06731,1.50766 -3.43123,4.21105 -9.09795,6.81046 -14.55672,6.81046 -9.66981,0 -17.052148,-7.48631 -18.663785,-16.11636 h 37.847465 c 3.0673,0 4.00309,-2.59941 4.00309,-5.82269 0,-13.51695 -11.17748,-24.38249 -24.3825,-24.38249 -14.348758,0 -25.630213,12.3732 -25.630213,26.61799 0,14.97262 11.853326,27.50179 26.929923,27.50179 z M 128.1682,493.78521 H 94.375822 c 1.715613,-7.95421 8.526078,-14.71268 17.416068,-14.71268 8.52608,0 15.38853,6.60251 16.37631,14.71268 z" /><path
+       inkscape:connector-curvature="0"
+       id="path4992"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Manjari;-inkscape-font-specification:Manjari;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 170.74659,471.17031 c -14.14081,0 -24.22653,12.63315 -24.22653,26.72197 0,14.14081 10.34566,27.50179 24.69443,27.50179 6.81046,0 12.47718,-4.00309 16.68823,-8.4221 v 23.4987 c 0,2.13152 1.7676,3.89912 3.89912,3.89912 2.18351,0 3.89912,-1.7676 3.89912,-3.89912 v -65.45323 c 0,-2.13152 -1.7676,-3.89912 -3.89912,-3.89912 -2.13152,0 -3.63918,1.7676 -3.63918,3.89912 l -0.25994,4.99087 c -3.95111,-4.00309 -9.87777,-8.838 -17.15613,-8.838 z m 0.15597,7.79824 c 10.55361,0 16.94817,9.82578 16.94817,19.65157 0,9.7218 -6.29058,18.97571 -16.74022,18.97571 -10.08573,0 -16.68824,-9.87777 -16.68824,-19.85952 0,-9.87777 6.60251,-18.76776 16.48029,-18.76776 z" /><path
+       inkscape:connector-curvature="0"
+       id="path4994"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Manjari;-inkscape-font-specification:Manjari;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 207.13838,498.20421 c 0,14.45274 11.17748,27.0339 25.68221,27.0339 10.6056,0 18.71577,-6.60251 22.19899,-14.24479 0.20795,-0.4159 0.36392,-1.14374 0.36392,-1.61163 0,-2.13152 -1.76761,-3.89912 -3.89912,-3.89912 -1.40369,0 -2.96334,1.03976 -3.53521,2.33947 -2.39146,5.19883 -7.90221,9.66982 -15.12858,9.66982 -10.13772,0 -17.93596,-9.04596 -17.93596,-19.23566 0,-10.1897 7.85023,-19.23566 17.93596,-19.23566 7.22637,0 12.68513,4.52298 15.0766,9.7218 0.57187,1.29971 2.13151,2.28749 3.5352,2.28749 2.13152,0 3.89912,-1.71561 3.89912,-3.84713 0,-0.4679 -0.20796,-1.24772 -0.41591,-1.66363 -3.48321,-7.64227 -11.48941,-14.24478 -22.09501,-14.24478 -14.40075,0 -25.68221,12.52917 -25.68221,26.92992 z" /><path
+       inkscape:connector-curvature="0"
+       id="path4996"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Manjari;-inkscape-font-specification:Manjari;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 291.72329,471.01434 c -14.50473,0 -25.94215,12.78912 -25.94215,27.24186 0,14.55671 11.38543,27.29384 26.1501,27.29384 14.55672,-0.10398 25.83817,-12.8411 25.83817,-27.29384 0,-14.50473 -11.48941,-27.24186 -26.04612,-27.24186 z m 0,7.79824 c 10.29368,0 18.24788,9.14994 18.24788,19.44362 0,10.29367 -7.85023,19.39162 -18.09192,19.4956 -10.44964,0 -18.29987,-9.20193 -18.29987,-19.59958 0,-10.24169 7.95421,-19.33964 18.14391,-19.33964 z" /><path
+       inkscape:connector-curvature="0"
+       id="path4998"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Manjari;-inkscape-font-specification:Manjari;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 332.84601,452.40254 c -1.97555,0 -3.63918,2.02755 -3.63918,4.05509 v 65.34925 c 0,2.28749 1.81959,3.89912 4.21105,3.89912 1.50766,0 3.58719,-1.50766 3.58719,-3.32725 v -66.0251 c 0,-1.87158 -1.61163,-3.95111 -4.15906,-3.95111 z" /></g><g
+     style="stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+     transform="translate(-90.575738,454.7035)"
+     id="g4722-6"><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path4-7"
+       d="m 96.122583,68.341188 c 0,5.870802 -4.761455,10.629242 -10.635272,10.629242 -5.873817,0 -10.635272,-4.75844 -10.635272,-10.629242 0,-5.870803 4.761455,-10.629243 10.635272,-10.629243 5.873817,0 10.635272,4.75844 10.635272,10.629243 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path6-5"
+       d="m -18.107109,68.341188 c 0,5.870802 -4.761454,10.629242 -10.635271,10.629242 -5.873818,0 -10.635272,-4.75844 -10.635272,-10.629242 0,-5.870803 4.761454,-10.629243 10.635272,-10.629243 5.873817,0 10.635271,4.75844 10.635271,10.629243 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path8-3"
+       d="m 71.826956,68.33968 c 0,1.416831 -1.148537,2.565368 -2.566875,2.565368 -1.418338,0 -2.566875,-1.148537 -2.566875,-2.565368 0,-1.41683 1.148537,-2.565367 2.566875,-2.565367 1.41683,0 2.566875,1.148537 2.566875,2.565367 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path10-5"
+       d="m 62.89188,68.33968 c 0,1.416831 -1.148537,2.565368 -2.566874,2.565368 -1.416831,0 -2.566875,-1.148537 -2.566875,-2.565368 0,-1.41683 1.150044,-2.565367 2.566875,-2.565367 1.418337,0 2.566874,1.148537 2.566874,2.565367 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path12-6"
+       d="m -0.79464689,68.33968 c 0,1.416831 -1.15004431,2.565368 -2.56687471,2.565368 -1.4168304,0 -2.5668747,-1.148537 -2.5668747,-2.565368 0,-1.41683 1.1500443,-2.565367 2.5668747,-2.565367 1.4168304,0 2.56687471,1.148537 2.56687471,2.565367 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path14-2"
+       d="m -9.7297221,68.33968 c 0,1.416831 -1.1485369,2.565368 -2.5668749,2.565368 -1.418337,0 -2.566874,-1.148537 -2.566874,-2.565368 0,-1.41683 1.148537,-2.565367 2.566874,-2.565367 1.418338,0 2.5668749,1.148537 2.5668749,2.565367 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path16-9"
+       d="m 28.37548,0.6257374 c 5.873817,0 10.635271,4.7599473 10.635271,10.6307496 0,5.870803 -4.761454,10.629243 -10.635271,10.629243 -5.873817,0 -10.635272,-4.75844 -10.635272,-10.629243 0,-5.8708023 4.761455,-10.6307496 10.635272,-10.6307496 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path20-1"
+       d="m 28.372465,24.909306 c 1.416831,0 2.566875,1.150045 2.566875,2.565368 0,1.41683 -1.150044,2.565367 -2.566875,2.565367 -1.41683,0 -2.566874,-1.14703 -2.566874,-2.565367 0,-1.416831 1.150044,-2.565368 2.566874,-2.565368 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path22-2"
+       d="m 28.372465,33.838353 c 1.416831,0 2.566875,1.148537 2.566875,2.565367 0,1.41683 -1.150044,2.565367 -2.566875,2.565367 -1.41683,0 -2.566874,-1.148537 -2.566874,-2.565367 0,-1.41683 1.150044,-2.565367 2.566874,-2.565367 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path28-7"
+       d="m 76.280928,20.46287 c 4.154026,4.149505 4.154026,10.880957 0,15.031968 -4.154026,4.152519 -10.888493,4.152519 -15.041012,0 -4.154026,-4.151011 -4.154026,-10.882463 0,-15.031968 4.154027,-4.152518 10.888493,-4.152518 15.041012,0 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path32-0"
+       d="m 59.099598,37.630635 c 1.002332,1.002332 1.002332,2.625658 0,3.626483 -1.002332,1.002332 -2.627165,1.002332 -3.629497,0 -1.002333,-1.002332 -1.002333,-2.625658 0,-3.626483 1.002332,-1.002332 2.627165,-1.002332 3.629497,0 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path34-9"
+       d="m 52.782645,43.944574 c 1.002332,1.002332 1.002332,2.627165 0,3.62799 -1.002333,1.002332 -2.627166,1.002332 -3.629498,0 -1.002332,-1.000825 -1.002332,-2.625658 0,-3.62799 1.000825,-1.00384 2.627165,-1.00384 3.629498,0 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path40-3"
+       d="m -19.531476,20.456841 c 4.154027,-4.151011 10.888493,-4.151011 15.0410119,0 4.15402619,4.151012 4.15402619,10.880957 0,15.033475 -4.1540262,4.151012 -10.8884929,4.151012 -15.0410119,0 -4.154026,-4.152518 -4.154026,-10.882463 0,-15.033475 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path44-6"
+       d="m -2.3531604,37.629128 c 1.0023322,-1.002333 2.62716538,-1.002333 3.6294975,0 1.0023322,1.002332 1.0023322,2.625658 0,3.626482 -1.00233212,1.002333 -2.6286726,1.002333 -3.6294975,0 -1.0038394,-1.000824 -1.0038394,-2.62415 0,-3.626482 z" /><path
+       inkscape:connector-curvature="0"
+       style="clip-rule:evenodd;fill:#00a900;fill-opacity:1;fill-rule:evenodd;stroke:#cccccc;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       id="path46-0"
+       d="m 3.9637931,43.941559 c 1.0023322,-1.002332 2.6271654,-1.002332 3.6294975,0 1.0023322,1.002332 1.0023322,2.627166 0,3.62799 -1.0023321,1.002333 -2.6271653,1.002333 -3.6294975,0 -1.0023321,-1.000824 -1.0023321,-2.625658 0,-3.62799 z" /><rect
+       style="opacity:1;vector-effect:none;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+       id="rect4636-6"
+       width="43.303108"
+       height="7.2103677"
+       x="6.2940488"
+       y="64.712517"
+       rx="1.9999999"
+       ry="2" /><rect
+       y="54.32959"
+       x="14.688103"
+       height="7.2103677"
+       width="26.515009"
+       id="rect4638-2"
+       style="opacity:1;vector-effect:none;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+       rx="1.9999999"
+       ry="2" /><rect
+       style="opacity:1;vector-effect:none;fill:#00a900;fill-opacity:1;stroke:#cccccc;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none"
+       id="rect4640-6"
+       width="11.326565"
+       height="7.2103677"
+       x="22.282328"
+       y="43.946659"
+       rx="1.9999999"
+       ry="2" /></g></g></svg>
\ No newline at end of file
diff --git a/seqcolapi/templates/base.html b/seqcolapi/templates/base.html
new file mode 100644
index 0000000..07a2ce8
--- /dev/null
+++ b/seqcolapi/templates/base.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+  	{% block head %}
+    <!-- Required meta tags -->
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>{% block title %}Sequence Collections API{% endblock %}</title>
+  	{% endblock %}
+  </head>
+  <body>
+		{% block nav %}
+		<nav class="navbar navbar-expand-md py-2 mb-4 border-bottom navbar-light" aria-label="navbar" style="background-color: #EFF3F6;">
+		  <div class="container">
+		    <a href="/" class="align-items-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none">
+		      <img src="/seqcol_logo.svg" alt="Sequence Collections" height="40"> Sequence collections
+		    </a>
+		    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+		      <span class="navbar-toggler-icon"></span>
+		    </button>
+		    <div class="collapse navbar-collapse me-auto" id="navbarSupportedContent">
+		      <ul class="navbar-nav ms-auto mb-2 mb-sm-0">        
+		      <li class="nav-item mx-2 my-0 h5">
+		        <a class="nav-link" href="/docs">API docs</a>
+		      </li>
+		      <li class="nav-item mx-2 my-0 h5">
+		      <a class="nav-link" href="https://github.com/refgenie/seqcol" target="_blank"><i class="fa fa-2x fa-github" aria-hidden="true"></i>GitHub</a>
+		      <li>
+		      </ul>
+		    </div>
+		  </div>
+		</nav>
+    {% endblock %}
+    <div class="container">
+    {% block content %}
+    No content
+    {% endblock %}
+	</div>
+		{% block footer %}
+		<div class="container">
+		  <footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top align-top">
+		  <span class="badge rounded-pill bg-secondary">seqcolapi {{seqcolapi_version}}</span>
+		  <span class="badge rounded-pill bg-secondary">seqcol {{seqcol_version}}</span>
+		  <span class="badge rounded-pill bg-secondary">
+		    Python {{python_version}}</span>
+
+		  <div class="ms-auto">
+		    <a href="https://databio.org/"><img src="static/logo_databio_long.svg" alt="Sheffield Computational Biology Lab" width="200"></a>
+		  </div>
+			</footer>
+		</div>
+		{% endblock %}
+  </body>	
+  	<!-- Bootstrap CSS -->
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
+    <!-- Custom CSS -->
+    <link rel="stylesheet" href="https://databio.org/css/databio.css">
+</html>
diff --git a/seqcolapi/templates/comparison_matrix.html b/seqcolapi/templates/comparison_matrix.html
new file mode 100644
index 0000000..1ff72d0
--- /dev/null
+++ b/seqcolapi/templates/comparison_matrix.html
@@ -0,0 +1,47 @@
+{% extends "base.html" %}
+{% block content %}
+<h3>Sequence collection comparison matrix</h3>
+
+The square matrix below lists sequence collections on the x and y axes. At the intersection is a link to the /comparison endpoint that compares those two genomes.
+
+<style>
+th.rotated-text {
+    height: 200px;
+    white-space: nowrap;
+    padding: 0 !important;
+}
+
+th.rotated-text > div {
+    transform:
+        translate(13px, 0px)
+        rotate(310deg);
+    width: 20px;
+}
+
+th.rotated-text > div > span {
+    padding: 5px 10px;
+}
+</style>
+
+<table class="table mt-5">
+<thead>
+  <th></th>
+  {% for x in results -%}
+  <th class="rotated-text"><div><span>{{ x }}</span></div></th>
+  {% endfor %}
+</thead>
+{%- for x in results -%}
+<tr>
+  <th><a href="{{ host }}/collection/{{results[x]['digest']}}">{{ x }}</a></th>
+{% for y in results %}
+	{% if x == y %}
+	<td>=</td>
+	{% else %}
+    <td><a href="{{ host }}/comparison/{{results[x]['digest']}}/{{results[y]['digest']}}">Compare</a></td>
+	{% endif %}
+{%- endfor %}
+</tr>
+{% endfor %}
+
+</table>
+{% endblock %}
\ No newline at end of file
diff --git a/seqcolapi/templates/index.html b/seqcolapi/templates/index.html
new file mode 100644
index 0000000..aa38984
--- /dev/null
+++ b/seqcolapi/templates/index.html
@@ -0,0 +1,22 @@
+{% extends "base.html" %}
+{% block title %}Sequence Collections API Demo{% endblock %}
+{% block content %}
+  <div>
+    <h1>Sequence Collections API Demo</h1>
+    <p id="welcome" class="text-justify">
+    Welcome to the Sequence Collections API. This server hosts an implementation of the <a href="https://seqcol.readthedocs.io/">GA4GH Sequence Collections specification (draft)</a>.</p>
+
+    <p>View the <a href="/docs">complete API documentation</a> or try these examples:<br><br>
+
+    <h3>Retrieving a sequence collection</h3>
+
+    See demos here:
+      <ul>
+        <li><a href="/links_demo.html">Small demo sequence collections</a></li>
+        <li><a href="/links_ref.html">Human reference sequence collections</a></li>
+        <li><a href="/seqcol_list.html">HPRC genomes</a></li>
+      
+      </ul>
+
+  </div>
+{% endblock %}
diff --git a/seqcolapi/templates/seqcol_list.html b/seqcolapi/templates/seqcol_list.html
new file mode 100644
index 0000000..4f116cd
--- /dev/null
+++ b/seqcolapi/templates/seqcol_list.html
@@ -0,0 +1,18 @@
+{% extends "base.html" %}
+{% block content %}
+<h3>Sequence collection list</h3>
+
+<table class="table mt-5">
+<thead>
+  <th>Assembly</th>
+  <th>Sequence collection digest</th>
+</thead>
+{%- for x in results -%}
+<tr>
+  <th><a href="{{x['assembly_link']}}">{{ x["assembly"] }}</a></th>
+  <th><a href="{{ host }}/collection/{{x['seqcol_digest']}}">{{ x["seqcol_digest"] }}</a></th>
+</tr>
+{% endfor %}
+
+</table>
+{% endblock %}
\ No newline at end of file


Test patch:
diff --git a/test_api/__init__.py b/test_api/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/test_api/collection/demo0_collection.json b/test_api/collection/demo0_collection.json
new file mode 100644
index 0000000..8bc1cac
--- /dev/null
+++ b/test_api/collection/demo0_collection.json
@@ -0,0 +1,22 @@
+{
+    "lengths": [
+      8,
+      4,
+      4
+    ],
+    "names": [
+      "chrX",
+      "chr1",
+      "chr2"
+    ],
+    "sequences": [
+      "SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw",
+      "SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj",
+      "SQ.AcLxtBuKEPk_7PGE_H4dGElwZHCujwH6"
+    ],
+    "sorted_name_length_pairs": [
+      "ESV_rcaJ-zgrfBr6sJ7J9kqldWX2gG_K",
+      "I0_AywNhq4XLlcc1vZexw5cHygCK_bLh",
+      "V2tENgwhEWrKc8UNgFzrMwx7H3JgoIuq"
+    ]
+}
diff --git a/test_api/collection/demo1_collection.json b/test_api/collection/demo1_collection.json
new file mode 100644
index 0000000..1d50798
--- /dev/null
+++ b/test_api/collection/demo1_collection.json
@@ -0,0 +1,18 @@
+{
+  "lengths": [
+      4,
+      4
+  ],
+  "names": [
+      "chr1",
+      "chr2"
+  ],
+  "sequences": [
+      "SQ.aKF498dAxcJAqme6QYQ7EZ07-fiw8Kw2",
+      "SQ.ORLd3OQy8whca09ypkTExMc_ByFalnnO"
+  ],
+  "sorted_name_length_pairs": [
+      "I0_AywNhq4XLlcc1vZexw5cHygCK_bLh",
+      "V2tENgwhEWrKc8UNgFzrMwx7H3JgoIuq"
+  ]
+}
\ No newline at end of file
diff --git a/test_api/collection/demo2_collection.json b/test_api/collection/demo2_collection.json
new file mode 100644
index 0000000..79a681a
--- /dev/null
+++ b/test_api/collection/demo2_collection.json
@@ -0,0 +1,22 @@
+{
+  "lengths": [
+    4,
+    4,
+    8
+  ],
+  "names": [
+    "chr1",
+    "chr2",
+    "chrX"
+  ],
+  "sequences": [
+    "SQ.aKF498dAxcJAqme6QYQ7EZ07-fiw8Kw2",
+    "SQ.ORLd3OQy8whca09ypkTExMc_ByFalnnO",
+    "SQ.733WIVstq8gdCl6w8NhKc5sGdN6SZ5-I"
+  ],
+  "sorted_name_length_pairs": [
+    "ESV_rcaJ-zgrfBr6sJ7J9kqldWX2gG_K",
+    "I0_AywNhq4XLlcc1vZexw5cHygCK_bLh",
+    "V2tENgwhEWrKc8UNgFzrMwx7H3JgoIuq"
+  ]
+}
\ No newline at end of file
diff --git a/test_api/collection/demo3_collection.json b/test_api/collection/demo3_collection.json
new file mode 100644
index 0000000..4735a12
--- /dev/null
+++ b/test_api/collection/demo3_collection.json
@@ -0,0 +1,22 @@
+{
+    "lengths": [
+      4,
+      4,
+      8
+    ],
+    "names": [
+      "1",
+      "2",
+      "X"
+    ],
+    "sequences": [
+      "SQ.aKF498dAxcJAqme6QYQ7EZ07-fiw8Kw2",
+      "SQ.ORLd3OQy8whca09ypkTExMc_ByFalnnO",
+      "SQ.733WIVstq8gdCl6w8NhKc5sGdN6SZ5-I"
+    ],
+    "sorted_name_length_pairs": [
+      "FD2SCYHfvC0UE3PYFnavbAR3I76wtI5x",
+      "rkhUjVQn9nSaQ-FVrlxVBlc7nqifKvUk",
+      "zbEAQ7f3J3xyW-jWvzXeLKFc1qS-zh0h"
+    ]
+  }
\ No newline at end of file
diff --git a/test_api/collection/demo4_collection.json b/test_api/collection/demo4_collection.json
new file mode 100644
index 0000000..1430b15
--- /dev/null
+++ b/test_api/collection/demo4_collection.json
@@ -0,0 +1,22 @@
+{
+  "lengths": [
+    4,
+    4,
+    8
+  ],
+  "names": [
+    "chr2",
+    "chr1",
+    "chrX"
+  ],
+  "sequences": [
+    "SQ.aKF498dAxcJAqme6QYQ7EZ07-fiw8Kw2",
+    "SQ.ORLd3OQy8whca09ypkTExMc_ByFalnnO",
+    "SQ.733WIVstq8gdCl6w8NhKc5sGdN6SZ5-I"
+  ],
+  "sorted_name_length_pairs": [
+    "ESV_rcaJ-zgrfBr6sJ7J9kqldWX2gG_K",
+    "I0_AywNhq4XLlcc1vZexw5cHygCK_bLh",
+    "V2tENgwhEWrKc8UNgFzrMwx7H3JgoIuq"
+  ]
+}
\ No newline at end of file
diff --git a/test_api/collection/demo5_collection.json b/test_api/collection/demo5_collection.json
new file mode 100644
index 0000000..a4bcb7b
--- /dev/null
+++ b/test_api/collection/demo5_collection.json
@@ -0,0 +1,22 @@
+{
+    "lengths": [
+      4,
+      4,
+      8
+    ],
+    "names": [
+      "chr1",
+      "chr2",
+      "chrX"
+    ],
+    "sequences": [
+      "SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj",
+      "SQ.AcLxtBuKEPk_7PGE_H4dGElwZHCujwH6",
+      "SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw"
+    ],
+    "sorted_name_length_pairs": [
+      "ESV_rcaJ-zgrfBr6sJ7J9kqldWX2gG_K",
+      "I0_AywNhq4XLlcc1vZexw5cHygCK_bLh",
+      "V2tENgwhEWrKc8UNgFzrMwx7H3JgoIuq"
+    ]
+  }
\ No newline at end of file
diff --git a/test_api/collection/demo6_collection.json b/test_api/collection/demo6_collection.json
new file mode 100644
index 0000000..b19cd1f
--- /dev/null
+++ b/test_api/collection/demo6_collection.json
@@ -0,0 +1,22 @@
+{
+    "lengths": [
+      8,
+      4,
+      4
+    ],
+    "names": [
+      "chrX",
+      "chr1",
+      "chr2"
+    ],
+    "sequences": [
+      "SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw",
+      "SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj",
+      "SQ.AcLxtBuKEPk_7PGE_H4dGElwZHCujwH6"
+    ],
+    "sorted_name_length_pairs": [
+      "ESV_rcaJ-zgrfBr6sJ7J9kqldWX2gG_K",
+      "I0_AywNhq4XLlcc1vZexw5cHygCK_bLh",
+      "V2tENgwhEWrKc8UNgFzrMwx7H3JgoIuq"
+    ]
+  }
\ No newline at end of file
diff --git a/test_api/comparison/0-vs-1-comparison.json b/test_api/comparison/0-vs-1-comparison.json
new file mode 100644
index 0000000..b3a3086
--- /dev/null
+++ b/test_api/comparison/0-vs-1-comparison.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32",
+    "b": "5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "b": {
+      "lengths": 2,
+      "names": 2,
+      "sequences": 2,
+      "sorted_name_length_pairs": 2
+    },
+    "a_and_b": {
+      "lengths": 2,
+      "names": 2,
+      "sequences": 0,
+      "sorted_name_length_pairs": 2
+    },
+    "a_and_b_same_order": {
+      "lengths": true,
+      "names": true,
+      "sequences": null,
+      "sorted_name_length_pairs": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/comparison/0-vs-2-comparison.json b/test_api/comparison/0-vs-2-comparison.json
new file mode 100644
index 0000000..f34c9e3
--- /dev/null
+++ b/test_api/comparison/0-vs-2-comparison.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32",
+    "b": "V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 0,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b_same_order": {
+      "lengths": false,
+      "names": false,
+      "sequences": null,
+      "sorted_name_length_pairs": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/comparison/1-vs-2-comparison.json b/test_api/comparison/1-vs-2-comparison.json
new file mode 100644
index 0000000..7db299f
--- /dev/null
+++ b/test_api/comparison/1-vs-2-comparison.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "5TK2xeaOB3WmheaDFTzE6G2zdStHNQCM",
+    "b": "V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 2,
+      "names": 2,
+      "sequences": 2,
+      "sorted_name_length_pairs": 2
+    },
+    "b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b": {
+      "lengths": 2,
+      "names": 2,
+      "sequences": 2,
+      "sorted_name_length_pairs": 2
+    },
+    "a_and_b_same_order": {
+      "lengths": true,
+      "names": true,
+      "sequences": true,
+      "sorted_name_length_pairs": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/comparison/2-vs-3-comparison.json b/test_api/comparison/2-vs-3-comparison.json
new file mode 100644
index 0000000..07e28a0
--- /dev/null
+++ b/test_api/comparison/2-vs-3-comparison.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "V7QPcpp5S1wYnPBmMGiO53LXRxr9tTQa",
+    "b": "_G-IybZWJOcCWYagm6qmjQTaRsKhNRT2"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b": {
+      "lengths": 3,
+      "names": 0,
+      "sequences": 3,
+      "sorted_name_length_pairs": 0
+    },
+    "a_and_b_same_order": {
+      "lengths": true,
+      "names": null,
+      "sequences": true,
+      "sorted_name_length_pairs": null
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/comparison/5-vs-6-comparison.json b/test_api/comparison/5-vs-6-comparison.json
new file mode 100644
index 0000000..90aafaa
--- /dev/null
+++ b/test_api/comparison/5-vs-6-comparison.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW",
+    "b": "fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b_same_order": {
+      "lengths": false,
+      "names": false,
+      "sequences": false,
+      "sorted_name_length_pairs": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/comparison/compare_different_names.json b/test_api/comparison/compare_different_names.json
new file mode 100644
index 0000000..236c507
--- /dev/null
+++ b/test_api/comparison/compare_different_names.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32",
+    "b": "TKB7n_14iKSFjljBA-TSVjeYpxPQe0-k"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b": {
+      "lengths": 3,
+      "names": 0,
+      "sequences": 3,
+      "sorted_name_length_pairs": 0
+    },
+    "a_and_b_same_order": {
+      "lengths": true,
+      "names": null,
+      "sequences": true,
+      "sorted_name_length_pairs": null
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/comparison/compare_different_order.json b/test_api/comparison/compare_different_order.json
new file mode 100644
index 0000000..0f28b06
--- /dev/null
+++ b/test_api/comparison/compare_different_order.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32",
+    "b": "JPd9Y-hwnhGD7HPe3yka4Qtx2YsIL8tW"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b_same_order": {
+      "lengths": false,
+      "names": false,
+      "sequences": false,
+      "sorted_name_length_pairs": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/comparison/compare_pair_swap.json b/test_api/comparison/compare_pair_swap.json
new file mode 100644
index 0000000..0f95343
--- /dev/null
+++ b/test_api/comparison/compare_pair_swap.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32",
+    "b": "E6zGtGuc8wKYmCMw5gaLW3ppyXsoO6p4"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 1
+    },
+    "a_and_b_same_order": {
+      "lengths": true,
+      "names": false,
+      "sequences": true,
+      "sorted_name_length_pairs": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/comparison/compare_subset.json b/test_api/comparison/compare_subset.json
new file mode 100644
index 0000000..3063daa
--- /dev/null
+++ b/test_api/comparison/compare_subset.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32",
+    "b": "8aA37TYgiVohRqfRhXEeklIAXf2Rs8jw"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "b": {
+      "lengths": 2,
+      "names": 2,
+      "sequences": 2,
+      "sorted_name_length_pairs": 2
+    },
+    "a_and_b": {
+      "lengths": 2,
+      "names": 2,
+      "sequences": 2,
+      "sorted_name_length_pairs": 2
+    },
+    "a_and_b_same_order": {
+      "lengths": null,
+      "names": true,
+      "sequences": true,
+      "sorted_name_length_pairs": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/comparison/compare_swap_wo_coords.json b/test_api/comparison/compare_swap_wo_coords.json
new file mode 100644
index 0000000..1339b13
--- /dev/null
+++ b/test_api/comparison/compare_swap_wo_coords.json
@@ -0,0 +1,42 @@
+{
+  "digests": {
+    "a": "fLf5M0BOIPIqcfbE6R8oYwxsy-PnoV32",
+    "b": "EkMSPx-_MdAzj2tWGfdFSVsuv03OznPn"
+  },
+  "attributes": {
+    "a_only": [],
+    "b_only": [],
+    "a_and_b": [
+      "lengths",
+      "names",
+      "sequences",
+      "sorted_name_length_pairs"
+    ]
+  },
+  "array_elements": {
+    "a": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b": {
+      "lengths": 3,
+      "names": 3,
+      "sequences": 3,
+      "sorted_name_length_pairs": 3
+    },
+    "a_and_b_same_order": {
+      "lengths": true,
+      "names": false,
+      "sequences": true,
+      "sorted_name_length_pairs": true
+    }
+  }
+}
\ No newline at end of file
diff --git a/test_api/conftest.py b/test_api/conftest.py
new file mode 100644
index 0000000..e5fb69e
--- /dev/null
+++ b/test_api/conftest.py
@@ -0,0 +1,57 @@
+import pytest
+import requests
+
+
+def pytest_addoption(parser):
+    """
+    Add an option to specify the API root
+    """
+    parser.addoption("--api_root", action="store", default="http://0.0.0.0:8100")
+
+
+@pytest.fixture()
+def api_root(pytestconfig):
+    """
+    Get the API root from the command line argument, --api_root
+    """
+    return pytestconfig.getoption("api_root")
+
+
+def check_server_is_running(api_root):
+    """
+    Check if a server is responding at the given API root
+    """
+    try:
+        print(f"Checking if service is running at {api_root}")
+        res = requests.get(f"{api_root}/")
+        assert res.status_code == 200, "Service is not running"
+        return True
+    except:
+        return False
+
+
+REQ_SERVICE_MARK = "require_service"
+
+
+def pytest_configure(config):
+    """
+    Register a custom marker for tests that require a server.
+    You can add this marker to a test with `@pytest.mark.require_service`,
+    and it will be skipped if the server is not running.
+    """
+    config.addinivalue_line(
+        "markers", f"{REQ_SERVICE_MARK}: test to only run when API root is available"
+    )
+
+
+def pytest_collection_modifyitems(config, items):
+    """
+    Skip tests marked with `@pytest.mark.require_service` if the server is not running
+    """
+    api_root = config.getoption("api_root")
+    skip_missing_service = pytest.mark.skip(reason="need API to run")
+    if not check_server_is_running(api_root):
+        print("Skipping tests that require a server to be running...")
+        for item in items:
+            if REQ_SERVICE_MARK in item.keywords:
+                item.add_marker(skip_missing_service)
diff --git a/test_api/test_compliance.py b/test_api/test_compliance.py
new file mode 100644
index 0000000..97f884b
--- /dev/null
+++ b/test_api/test_compliance.py
@@ -0,0 +1,115 @@
+# Draft of a compliance suite for the API
+
+import json
+import pytest
+import requests
+
+# Collection endpoints
+DEMO_FILES = [
+    "demo0.fa",
+    "demo1.fa.gz",
+    "demo2.fa",
+    "demo3.fa",
+    "demo4.fa",
+    "demo5.fa.gz",
+    "demo6.fa",
+]
+
+API_TEST_DIR = "test_api"
+
+COLLECTION_TESTS = [
+    (DEMO_FILES[0], f"{API_TEST_DIR}/collection/demo0_collection.json"),
+    (DEMO_FILES[1], f"{API_TEST_DIR}/collection/demo1_collection.json"),
+    (DEMO_FILES[2], f"{API_TEST_DIR}/collection/demo2_collection.json"),
+    (DEMO_FILES[3], f"{API_TEST_DIR}/collection/demo3_collection.json"),
+    (DEMO_FILES[4], f"{API_TEST_DIR}/collection/demo4_collection.json"),
+    (DEMO_FILES[5], f"{API_TEST_DIR}/collection/demo5_collection.json"),
+    (DEMO_FILES[6], f"{API_TEST_DIR}/collection/demo6_collection.json"),
+]
+
+COMPARISON_TESTS = [
+    f"{API_TEST_DIR}/comparison/compare_subset.json",  # subset
+    f"{API_TEST_DIR}/comparison/compare_different_names.json",  # same sequences, different names
+    f"{API_TEST_DIR}/comparison/compare_different_order.json",  # same sequences, name order switch, but equivalent coordinate system
+    f"{API_TEST_DIR}/comparison/compare_pair_swap.json",  # swapped name-length-pairs
+    f"{API_TEST_DIR}/comparison/compare_swap_wo_coords.json",  # swapped name-length-pairs, but no coord system change
+]
+
+# This is optional, so we could turn off for a compliance test
+TEST_SORTED_NAME_LENGTH_PAIRS = True
+
+# api_root = "http://0.0.0.0:8100"
+demo_root = "/home/nsheff/code/refget/demo_fasta"
+demo_file = "demo0.fa"
+response_file = "tests/demo0_collection.json"
+import refget
+
+
+def read_url(url):
+    import yaml
+
+    print("Reading URL: {}".format(url))
+    from urllib.request import urlopen
+    from urllib.error import HTTPError
+
+    try:
+        response = urlopen(url)
+    except HTTPError as e:
+        raise e
+    data = response.read()  # a `bytes` object
+    text = data.decode("utf-8")
+    print(text)
+    return yaml.safe_load(text)
+
+
+def check_collection(api_root, demo_file, response_file):
+
+    # Need schema to make sure we eliminate inherent attributes correctly
+    schema_path = "https://schema.databio.org/refget/SeqColArraySetInherent.yaml"
+
+    schema = read_url(schema_path)
+    print(f"Loading fasta file at '{demo_root}/{demo_file}'")
+    digest = refget.fasta_file_to_digest(f"{demo_root}/{demo_file}", schema=schema)
+    print(f"Checking digest: {digest}")
+    res = requests.get(f"{api_root}/collection/{digest}")
+    server_answer = json.loads(res.content)
+    with open(response_file) as fp:
+        correct_answer = json.load(fp)
+
+    assert (
+        server_answer["sequences"] == correct_answer["sequences"]
+    ), f"Collection endpoint failed: sequence mismatch for {demo_file}"
+    assert (
+        server_answer["names"] == correct_answer["names"]
+    ), f"Collection endpoint failed: names mismatch for {demo_file}"
+    assert (
+        server_answer["lengths"] == correct_answer["lengths"]
+    ), f"Collection endpoint failed: lengths mismatch for {demo_file}"
+    if TEST_SORTED_NAME_LENGTH_PAIRS:
+        assert (
+            server_answer["sorted_name_length_pairs"] == correct_answer["sorted_name_length_pairs"]
+        ), f"Collection endpoint failed: sorted_name_length_pairs mismatch for {demo_file}"
+
+
+def check_comparison(api_root, response_file):
+    with open(response_file) as fp:
+        correct_answer = json.load(fp)
+    res = requests.get(
+        f"{api_root}/comparison/{correct_answer['digests']['a']}/{correct_answer['digests']['b']}"
+    )
+    server_answer = json.loads(res.content)
+    assert server_answer == correct_answer, "Comparison endpoint failed"
+
+
+@pytest.mark.require_service
+class TestAPI:
+
+    @pytest.mark.parametrize("test_values", COLLECTION_TESTS)
+    def test_collection_endpoint(self, api_root, test_values):
+        # print("Service unavailable: ", SERVICE_UNAVAILABLE)
+        check_collection(api_root, *test_values)
+
+    @pytest.mark.parametrize("response_file", COMPARISON_TESTS)
+    def test_comparison_endpoint(self, api_root, response_file):
+        # print("Service unavailable: ", SERVICE_UNAVAILABLE)
+        check_comparison(api_root, response_file)
diff --git a/test_fasta/base.fa b/test_fasta/base.fa
new file mode 100644
index 0000000..dd08063
--- /dev/null
+++ b/test_fasta/base.fa
@@ -0,0 +1,6 @@
+>chrX
+TTGGGGAA
+>chr1
+GGAA
+>chr2
+GCGC
diff --git a/test_fasta/base.fa.checksums b/test_fasta/base.fa.checksums
new file mode 100644
index 0000000..35a2aba
--- /dev/null
+++ b/test_fasta/base.fa.checksums
@@ -0,0 +1,3 @@
+chrX	8	SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw	5f63cfaa3ef61f88c9635fb9d18ec945
+chr1	4	SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj	31fc6ca291a32fb9df82b85e5f077e31
+chr2	4	SQ.AcLxtBuKEPk_7PGE_H4dGElwZHCujwH6	92c6a56c9e9459d8a42b96f7884710bc
diff --git a/test_fasta/different_names.fa b/test_fasta/different_names.fa
new file mode 100644
index 0000000..0358591
--- /dev/null
+++ b/test_fasta/different_names.fa
@@ -0,0 +1,6 @@
+>X
+TTGGGGAA
+>1
+GGAA
+>2
+GCGC
diff --git a/test_fasta/different_names.fa.checksums b/test_fasta/different_names.fa.checksums
new file mode 100644
index 0000000..59e84c7
--- /dev/null
+++ b/test_fasta/different_names.fa.checksums
@@ -0,0 +1,3 @@
+X	8	SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw	5f63cfaa3ef61f88c9635fb9d18ec945
+1	4	SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj	31fc6ca291a32fb9df82b85e5f077e31
+2	4	SQ.AcLxtBuKEPk_7PGE_H4dGElwZHCujwH6	92c6a56c9e9459d8a42b96f7884710bc
diff --git a/test_fasta/different_order.fa b/test_fasta/different_order.fa
new file mode 100644
index 0000000..2a462d4
--- /dev/null
+++ b/test_fasta/different_order.fa
@@ -0,0 +1,6 @@
+>chr1
+GGAA
+>chr2
+GCGC
+>chrX
+TTGGGGAA
diff --git a/test_fasta/different_order.fa.checksums b/test_fasta/different_order.fa.checksums
new file mode 100644
index 0000000..b9fccde
--- /dev/null
+++ b/test_fasta/different_order.fa.checksums
@@ -0,0 +1,3 @@
+chr1	4	SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj	31fc6ca291a32fb9df82b85e5f077e31
+chr2	4	SQ.AcLxtBuKEPk_7PGE_H4dGElwZHCujwH6	92c6a56c9e9459d8a42b96f7884710bc
+chrX	8	SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw	5f63cfaa3ef61f88c9635fb9d18ec945
diff --git a/test_fasta/pair_swap.fa b/test_fasta/pair_swap.fa
new file mode 100644
index 0000000..51ceaad
--- /dev/null
+++ b/test_fasta/pair_swap.fa
@@ -0,0 +1,6 @@
+>chr2
+TTGGGGAA
+>chr1
+GGAA
+>chrX
+GCGC
diff --git a/test_fasta/pair_swap.fa.checksums b/test_fasta/pair_swap.fa.checksums
new file mode 100644
index 0000000..8886cb9
--- /dev/null
+++ b/test_fasta/pair_swap.fa.checksums
@@ -0,0 +1,3 @@
+chr2	8	SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw	5f63cfaa3ef61f88c9635fb9d18ec945
+chr1	4	SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj	31fc6ca291a32fb9df82b85e5f077e31
+chrX	4	SQ.AcLxtBuKEPk_7PGE_H4dGElwZHCujwH6	92c6a56c9e9459d8a42b96f7884710bc
diff --git a/test_fasta/subset.fa b/test_fasta/subset.fa
new file mode 100644
index 0000000..e036031
--- /dev/null
+++ b/test_fasta/subset.fa
@@ -0,0 +1,4 @@
+>chrX
+TTGGGGAA
+>chr1
+GGAA
diff --git a/test_fasta/subset.fa.checksums b/test_fasta/subset.fa.checksums
new file mode 100644
index 0000000..e5f4c86
--- /dev/null
+++ b/test_fasta/subset.fa.checksums
@@ -0,0 +1,2 @@
+chrX	8	SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw	5f63cfaa3ef61f88c9635fb9d18ec945
+chr1	4	SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj	31fc6ca291a32fb9df82b85e5f077e31
diff --git a/test_fasta/swap_coords.fa.checksums b/test_fasta/swap_coords.fa.checksums
new file mode 100644
index 0000000..36b8f8f
--- /dev/null
+++ b/test_fasta/swap_coords.fa.checksums
@@ -0,0 +1,3 @@
+chrX	8	SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw	5f63cfaa3ef61f88c9635fb9d18ec945
+chr2	4	SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj	31fc6ca291a32fb9df82b85e5f077e31
+chr1	4	SQ.AcLxtBuKEPk_7PGE_H4dGElwZHCujwH6	92c6a56c9e9459d8a42b96f7884710bc
diff --git a/test_fasta/swap_wo_coords.fa b/test_fasta/swap_wo_coords.fa
new file mode 100644
index 0000000..979307d
--- /dev/null
+++ b/test_fasta/swap_wo_coords.fa
@@ -0,0 +1,6 @@
+>chrX
+TTGGGGAA
+>chr2
+GGAA
+>chr1
+GCGC
diff --git a/test_fasta/swap_wo_coords.fa.checksums b/test_fasta/swap_wo_coords.fa.checksums
new file mode 100644
index 0000000..36b8f8f
--- /dev/null
+++ b/test_fasta/swap_wo_coords.fa.checksums
@@ -0,0 +1,3 @@
+chrX	8	SQ.iYtREV555dUFKg2_agSJW6suquUyPpMw	5f63cfaa3ef61f88c9635fb9d18ec945
+chr2	4	SQ.YBbVX0dLKG1ieEDCiMmkrTZFt_Z5Vdaj	31fc6ca291a32fb9df82b85e5f077e31
+chr1	4	SQ.AcLxtBuKEPk_7PGE_H4dGElwZHCujwH6	92c6a56c9e9459d8a42b96f7884710bc