Files
2025-11-30 08:30:10 +08:00

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: Success
  • 201 Created: Resource created
  • 400 Bad Request: Invalid parameters
  • 401 Unauthorized: Missing or invalid credentials
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Resource doesn't exist
  • 422 Unprocessable Entity: Validation error
  • 429 Too Many Requests: Rate limit exceeded
  • 500 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 requests
    • X-RateLimit-Remaining: Remaining requests
    • X-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 match
  • modifiedAt: ISO 8601 datetime
  • createdAt: ISO 8601 datetime
  • schemaId: Filter by schema
  • folderId: Filter by folder
  • archived: 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

  1. Use appropriate page sizes:

    • Default: 50 items
    • Max: 100 items
    • Adjust based on needs
  2. Filter on server-side:

    • Use query parameters instead of client filtering
    • Reduces data transfer and processing
  3. 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