14 KiB
Benchling REST API Endpoints Reference
Base URL
All API requests use the base URL format:
https://{tenant}.benchling.com/api/v2
Replace {tenant} with your Benchling tenant name.
API Versioning
Current API version: v2 (2025-10-07)
The API version is specified in the URL path. Benchling maintains backward compatibility within a major version.
Authentication
All requests require authentication via HTTP headers:
API Key (Basic Auth):
curl -X GET \
https://your-tenant.benchling.com/api/v2/dna-sequences \
-u "your_api_key:"
OAuth Bearer Token:
curl -X GET \
https://your-tenant.benchling.com/api/v2/dna-sequences \
-H "Authorization: Bearer your_access_token"
Common Headers
Authorization: Bearer {token}
Content-Type: application/json
Accept: application/json
Response Format
All responses follow a consistent JSON structure:
Single Resource:
{
"id": "seq_abc123",
"name": "My Sequence",
"bases": "ATCGATCG",
...
}
List Response:
{
"results": [
{"id": "seq_1", "name": "Sequence 1"},
{"id": "seq_2", "name": "Sequence 2"}
],
"nextToken": "token_for_next_page"
}
Pagination
List endpoints support pagination:
Query Parameters:
pageSize: Number of items per page (default: 50, max: 100)nextToken: Token from previous response for next page
Example:
curl -X GET \
"https://your-tenant.benchling.com/api/v2/dna-sequences?pageSize=50&nextToken=abc123"
Error Responses
Format:
{
"error": {
"type": "NotFoundError",
"message": "DNA sequence not found",
"userMessage": "The requested sequence does not exist or you don't have access"
}
}
Common Status Codes:
200 OK: Success201 Created: Resource created400 Bad Request: Invalid parameters401 Unauthorized: Missing or invalid credentials403 Forbidden: Insufficient permissions404 Not Found: Resource doesn't exist422 Unprocessable Entity: Validation error429 Too Many Requests: Rate limit exceeded500 Internal Server Error: Server error
Core Endpoints
DNA Sequences
List DNA Sequences:
GET /api/v2/dna-sequences
Query Parameters:
- pageSize: integer (default: 50, max: 100)
- nextToken: string
- folderId: string
- schemaId: string
- name: string (filter by name)
- modifiedAt: string (ISO 8601 date)
Get DNA Sequence:
GET /api/v2/dna-sequences/{sequenceId}
Create DNA Sequence:
POST /api/v2/dna-sequences
Body:
{
"name": "My Plasmid",
"bases": "ATCGATCG",
"isCircular": true,
"folderId": "fld_abc123",
"schemaId": "ts_abc123",
"fields": {
"gene_name": {"value": "GFP"},
"resistance": {"value": "Kanamycin"}
},
"entityRegistryId": "src_abc123", // optional for registration
"namingStrategy": "NEW_IDS" // optional for registration
}
Update DNA Sequence:
PATCH /api/v2/dna-sequences/{sequenceId}
Body:
{
"name": "Updated Plasmid",
"fields": {
"gene_name": {"value": "mCherry"}
}
}
Archive DNA Sequence:
POST /api/v2/dna-sequences:archive
Body:
{
"dnaSequenceIds": ["seq_abc123"],
"reason": "Deprecated construct"
}
RNA Sequences
List RNA Sequences:
GET /api/v2/rna-sequences
Get RNA Sequence:
GET /api/v2/rna-sequences/{sequenceId}
Create RNA Sequence:
POST /api/v2/rna-sequences
Body:
{
"name": "gRNA-001",
"bases": "AUCGAUCG",
"folderId": "fld_abc123",
"fields": {
"target_gene": {"value": "TP53"}
}
}
Update RNA Sequence:
PATCH /api/v2/rna-sequences/{sequenceId}
Archive RNA Sequence:
POST /api/v2/rna-sequences:archive
Amino Acid (Protein) Sequences
List AA Sequences:
GET /api/v2/aa-sequences
Get AA Sequence:
GET /api/v2/aa-sequences/{sequenceId}
Create AA Sequence:
POST /api/v2/aa-sequences
Body:
{
"name": "GFP Protein",
"aminoAcids": "MSKGEELFTGVVPILVELDGDVNGHKF",
"folderId": "fld_abc123"
}
Custom Entities
List Custom Entities:
GET /api/v2/custom-entities
Query Parameters:
- schemaId: string (required to filter by type)
- pageSize: integer
- nextToken: string
Get Custom Entity:
GET /api/v2/custom-entities/{entityId}
Create Custom Entity:
POST /api/v2/custom-entities
Body:
{
"name": "HEK293T-Clone5",
"schemaId": "ts_cellline_abc",
"folderId": "fld_abc123",
"fields": {
"passage_number": {"value": "15"},
"mycoplasma_test": {"value": "Negative"}
}
}
Update Custom Entity:
PATCH /api/v2/custom-entities/{entityId}
Body:
{
"fields": {
"passage_number": {"value": "16"}
}
}
Mixtures
List Mixtures:
GET /api/v2/mixtures
Create Mixture:
POST /api/v2/mixtures
Body:
{
"name": "LB-Amp Media",
"folderId": "fld_abc123",
"schemaId": "ts_mixture_abc",
"ingredients": [
{
"componentEntityId": "ent_lb_base",
"amount": {"value": "1000", "units": "mL"}
},
{
"componentEntityId": "ent_ampicillin",
"amount": {"value": "100", "units": "mg"}
}
]
}
Containers
List Containers:
GET /api/v2/containers
Query Parameters:
- parentStorageId: string (filter by location/box)
- schemaId: string
- barcode: string
Get Container:
GET /api/v2/containers/{containerId}
Create Container:
POST /api/v2/containers
Body:
{
"name": "Sample-001",
"schemaId": "cont_schema_abc",
"barcode": "CONT001",
"parentStorageId": "box_abc123",
"fields": {
"concentration": {"value": "100 ng/μL"},
"volume": {"value": "50 μL"}
}
}
Update Container:
PATCH /api/v2/containers/{containerId}
Body:
{
"fields": {
"volume": {"value": "45 μL"}
}
}
Transfer Container:
POST /api/v2/containers:transfer
Body:
{
"containerIds": ["cont_abc123"],
"destinationStorageId": "box_xyz789"
}
Check Out Container:
POST /api/v2/containers:checkout
Body:
{
"containerIds": ["cont_abc123"],
"comment": "Taking to bench"
}
Check In Container:
POST /api/v2/containers:checkin
Body:
{
"containerIds": ["cont_abc123"],
"locationId": "bench_loc_abc"
}
Boxes
List Boxes:
GET /api/v2/boxes
Query Parameters:
- parentStorageId: string
- schemaId: string
Get Box:
GET /api/v2/boxes/{boxId}
Create Box:
POST /api/v2/boxes
Body:
{
"name": "Freezer-A-Box-01",
"schemaId": "box_schema_abc",
"parentStorageId": "loc_freezer_a",
"barcode": "BOX001"
}
Locations
List Locations:
GET /api/v2/locations
Get Location:
GET /api/v2/locations/{locationId}
Create Location:
POST /api/v2/locations
Body:
{
"name": "Freezer A - Shelf 2",
"parentStorageId": "loc_freezer_a",
"barcode": "LOC-A-S2"
}
Plates
List Plates:
GET /api/v2/plates
Get Plate:
GET /api/v2/plates/{plateId}
Create Plate:
POST /api/v2/plates
Body:
{
"name": "PCR-Plate-001",
"schemaId": "plate_schema_abc",
"barcode": "PLATE001",
"wells": [
{"position": "A1", "entityId": "ent_abc"},
{"position": "A2", "entityId": "ent_xyz"}
]
}
Entries (Notebook)
List Entries:
GET /api/v2/entries
Query Parameters:
- folderId: string
- schemaId: string
- modifiedAt: string
Get Entry:
GET /api/v2/entries/{entryId}
Create Entry:
POST /api/v2/entries
Body:
{
"name": "Experiment 2025-10-20",
"folderId": "fld_abc123",
"schemaId": "entry_schema_abc",
"fields": {
"objective": {"value": "Test gene expression"},
"date": {"value": "2025-10-20"}
}
}
Update Entry:
PATCH /api/v2/entries/{entryId}
Body:
{
"fields": {
"results": {"value": "Successful expression"}
}
}
Workflow Tasks
List Workflow Tasks:
GET /api/v2/tasks
Query Parameters:
- workflowId: string
- statusIds: string[] (comma-separated)
- assigneeId: string
Get Task:
GET /api/v2/tasks/{taskId}
Create Task:
POST /api/v2/tasks
Body:
{
"name": "PCR Amplification",
"workflowId": "wf_abc123",
"assigneeId": "user_abc123",
"schemaId": "task_schema_abc",
"fields": {
"template": {"value": "seq_abc123"},
"priority": {"value": "High"}
}
}
Update Task:
PATCH /api/v2/tasks/{taskId}
Body:
{
"statusId": "status_complete_abc",
"fields": {
"completion_date": {"value": "2025-10-20"}
}
}
Folders
List Folders:
GET /api/v2/folders
Query Parameters:
- projectId: string
- parentFolderId: string
Get Folder:
GET /api/v2/folders/{folderId}
Create Folder:
POST /api/v2/folders
Body:
{
"name": "2025 Experiments",
"parentFolderId": "fld_parent_abc",
"projectId": "proj_abc123"
}
Projects
List Projects:
GET /api/v2/projects
Get Project:
GET /api/v2/projects/{projectId}
Users
Get Current User:
GET /api/v2/users/me
List Users:
GET /api/v2/users
Get User:
GET /api/v2/users/{userId}
Teams
List Teams:
GET /api/v2/teams
Get Team:
GET /api/v2/teams/{teamId}
Schemas
List Schemas:
GET /api/v2/schemas
Query Parameters:
- entityType: string (e.g., "dna_sequence", "custom_entity")
Get Schema:
GET /api/v2/schemas/{schemaId}
Registries
List Registries:
GET /api/v2/registries
Get Registry:
GET /api/v2/registries/{registryId}
Bulk Operations
Batch Archive
Archive Multiple Entities:
POST /api/v2/{entity-type}:archive
Body:
{
"{entity}Ids": ["id1", "id2", "id3"],
"reason": "Cleanup"
}
Batch Transfer
Transfer Multiple Containers:
POST /api/v2/containers:bulk-transfer
Body:
{
"transfers": [
{"containerId": "cont_1", "destinationId": "box_a"},
{"containerId": "cont_2", "destinationId": "box_b"}
]
}
Async Operations
Some operations return task IDs for async processing:
Response:
{
"taskId": "task_abc123"
}
Check Task Status:
GET /api/v2/tasks/{taskId}
Response:
{
"id": "task_abc123",
"status": "RUNNING", // or "SUCCEEDED", "FAILED"
"message": "Processing...",
"response": {...} // Available when status is SUCCEEDED
}
Field Value Format
Custom schema fields use a specific format:
Simple Value:
{
"field_name": {
"value": "Field Value"
}
}
Dropdown:
{
"dropdown_field": {
"value": "Option1" // Must match exact option name
}
}
Date:
{
"date_field": {
"value": "2025-10-20" // Format: YYYY-MM-DD
}
}
Entity Link:
{
"entity_link_field": {
"value": "seq_abc123" // Entity ID
}
}
Numeric:
{
"numeric_field": {
"value": "123.45" // String representation
}
}
Rate Limiting
Limits:
- Default: 100 requests per 10 seconds per user/app
- Rate limit headers included in responses:
X-RateLimit-Limit: Total allowed requestsX-RateLimit-Remaining: Remaining requestsX-RateLimit-Reset: Unix timestamp when limit resets
Handling 429 Responses:
{
"error": {
"type": "RateLimitError",
"message": "Rate limit exceeded",
"retryAfter": 5 // Seconds to wait
}
}
Filtering and Searching
Common Query Parameters:
name: Partial name matchmodifiedAt: ISO 8601 datetimecreatedAt: ISO 8601 datetimeschemaId: Filter by schemafolderId: Filter by folderarchived: Boolean (include archived items)
Example:
curl -X GET \
"https://tenant.benchling.com/api/v2/dna-sequences?name=plasmid&folderId=fld_abc&archived=false"
Best Practices
Request Efficiency
-
Use appropriate page sizes:
- Default: 50 items
- Max: 100 items
- Adjust based on needs
-
Filter on server-side:
- Use query parameters instead of client filtering
- Reduces data transfer and processing
-
Batch operations:
- Use bulk endpoints when available
- Archive/transfer multiple items in one request
Error Handling
// Example error handling
async function fetchSequence(id) {
try {
const response = await fetch(
`https://tenant.benchling.com/api/v2/dna-sequences/${id}`,
{
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
}
}
);
if (!response.ok) {
if (response.status === 429) {
// Rate limit - retry with backoff
const retryAfter = response.headers.get('Retry-After');
await sleep(retryAfter * 1000);
return fetchSequence(id);
} else if (response.status === 404) {
return null; // Not found
} else {
throw new Error(`API error: ${response.status}`);
}
}
return await response.json();
} catch (error) {
console.error('Request failed:', error);
throw error;
}
}
Pagination Loop
async function getAllSequences() {
let allSequences = [];
let nextToken = null;
do {
const url = new URL('https://tenant.benchling.com/api/v2/dna-sequences');
if (nextToken) {
url.searchParams.set('nextToken', nextToken);
}
url.searchParams.set('pageSize', '100');
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${token}`,
'Accept': 'application/json'
}
});
const data = await response.json();
allSequences = allSequences.concat(data.results);
nextToken = data.nextToken;
} while (nextToken);
return allSequences;
}
References
- API Documentation: https://benchling.com/api/reference
- Interactive API Explorer: https://your-tenant.benchling.com/api/reference (requires authentication)
- Changelog: https://docs.benchling.com/changelog