skills/benchling-integration/references/core_capabilities.md
The seven capability areas in full, with code: authentication and setup, registry and entity management, inventory management, notebook and documentation, workflows and automation, events and integration, and the data warehouse and analytics.
Python SDK installation:
uv pip install "benchling-sdk==1.25.0"
Preview builds (alpha; not for production):
uv pip install "benchling-sdk" --prerelease allow
Environment variables (scoped reads only):
Read only the named keys you need — never dump or iterate over the full environment:
import os
tenant_url = os.environ.get("BENCHLING_TENANT_URL") # e.g. https://your-tenant.benchling.com
api_key = os.environ.get("BENCHLING_API_KEY")
if not tenant_url or not api_key:
raise ValueError("Set BENCHLING_TENANT_URL and BENCHLING_API_KEY")
Obtain an API key from Profile Settings in Benchling. For OAuth apps, use the Developer Console and store BENCHLING_CLIENT_ID / BENCHLING_CLIENT_SECRET separately.
Authentication methods:
API key (scripts and personal automation):
from benchling_sdk.benchling import Benchling
from benchling_sdk.auth.api_key_auth import ApiKeyAuth
benchling = Benchling(
url=tenant_url,
auth_method=ApiKeyAuth(api_key),
)
OAuth client credentials (multi-user apps and production integrations):
from benchling_sdk.benchling import Benchling
from benchling_sdk.auth.client_credentials_oauth2 import ClientCredentialsOAuth2
benchling = Benchling(
url=tenant_url,
auth_method=ClientCredentialsOAuth2(
client_id=os.environ["BENCHLING_CLIENT_ID"],
client_secret=os.environ["BENCHLING_CLIENT_SECRET"],
),
)
Key points:
benchling.users.get_me() before bulk operationsFor detailed authentication information including OIDC and security best practices, refer to references/authentication.md.
Registry entities include DNA sequences, RNA sequences, AA sequences, custom entities, and mixtures. The SDK provides typed classes for creating and managing these entities.
Creating DNA Sequences:
from benchling_sdk.models import DnaSequenceCreate
sequence = benchling.dna_sequences.create(
DnaSequenceCreate(
name="My Plasmid",
bases="ATCGATCG",
is_circular=True,
folder_id="fld_abc123",
schema_id="ts_abc123", # optional
fields=benchling.models.fields({"gene_name": "GFP"})
)
)
Registry Registration:
To register an entity directly upon creation:
sequence = benchling.dna_sequences.create(
DnaSequenceCreate(
name="My Plasmid",
bases="ATCGATCG",
is_circular=True,
folder_id="fld_abc123",
entity_registry_id="src_abc123", # Registry to register in
naming_strategy="NEW_IDS" # or "IDS_FROM_NAMES"
)
)
Important: Use either entity_registry_id OR naming_strategy, never both.
Updating Entities:
from benchling_sdk.models import DnaSequenceUpdate
updated = benchling.dna_sequences.update(
sequence_id="seq_abc123",
dna_sequence=DnaSequenceUpdate(
name="Updated Plasmid Name",
fields=benchling.models.fields({"gene_name": "mCherry"})
)
)
Unspecified fields remain unchanged, allowing partial updates.
Listing and Pagination:
# List all DNA sequences (returns a generator)
sequences = benchling.dna_sequences.list()
for page in sequences:
for seq in page:
print(f"{seq.name} ({seq.id})")
# Check total count
total = sequences.estimated_count()
Key Operations:
benchling.<entity_type>.create()benchling.<entity_type>.get_by_id(id) or .list()benchling.<entity_type>.update(id, update_object)benchling.<entity_type>.archive(id)Entity types: dna_sequences, rna_sequences, aa_sequences, custom_entities, mixtures
For comprehensive SDK reference and advanced patterns, refer to references/sdk_reference.md.
Manage physical samples, containers, boxes, and locations within the Benchling inventory system.
Creating Containers:
from benchling_sdk.models import ContainerCreate
container = benchling.containers.create(
ContainerCreate(
name="Sample Tube 001",
schema_id="cont_schema_abc123",
parent_storage_id="box_abc123", # optional
fields=benchling.models.fields({"concentration": "100 ng/μL"})
)
)
Managing Boxes:
from benchling_sdk.models import BoxCreate
box = benchling.boxes.create(
BoxCreate(
name="Freezer Box A1",
schema_id="box_schema_abc123",
parent_storage_id="loc_abc123"
)
)
Transferring Items:
# Transfer a container to a new location
transfer = benchling.containers.transfer(
container_id="cont_abc123",
destination_id="box_xyz789"
)
Key Inventory Operations:
Interact with electronic lab notebook (ELN) entries, protocols, and templates.
Creating Notebook Entries:
from benchling_sdk.models import EntryCreate
entry = benchling.entries.create(
EntryCreate(
name="Experiment 2025-10-20",
folder_id="fld_abc123",
schema_id="entry_schema_abc123",
fields=benchling.models.fields({"objective": "Test gene expression"})
)
)
Linking Entities to Entries:
# Add references to entities in an entry
entry_link = benchling.entry_links.create(
entry_id="entry_abc123",
entity_id="seq_xyz789"
)
Key Notebook Operations:
Automate laboratory processes using Benchling's workflow system.
Creating Workflow Tasks:
from benchling_sdk.models import WorkflowTaskCreate
task = benchling.workflow_tasks.create(
WorkflowTaskCreate(
name="PCR Amplification",
workflow_id="wf_abc123",
assignee_id="user_abc123",
fields=benchling.models.fields({"template": "seq_abc123"})
)
)
Updating Task Status:
from benchling_sdk.models import WorkflowTaskUpdate
updated_task = benchling.workflow_tasks.update(
task_id="task_abc123",
workflow_task=WorkflowTaskUpdate(
status_id="status_complete_abc123"
)
)
Asynchronous Operations:
Some operations are asynchronous and return tasks. The SDK default max_wait_seconds for polling is 600 seconds (since SDK 1.11.0):
from benchling_sdk.helpers.tasks import wait_for_task
result = wait_for_task(
benchling,
task_id="task_abc123",
interval_wait_seconds=2,
max_wait_seconds=300, # override for long-running serverless handlers
)
Key Workflow Operations:
Subscribe to Benchling changes via AWS EventBridge (customer-owned bus) or Webhooks (recommended for new Benchling Apps). EventBridge delivers hydrated v2 API objects; webhooks use thinner payloads.
Common EventBridge detail-type values:
v2.dnaSequence.created, v2.dnaSequence.updatedv2.entity.registeredv2.entry.created, v2.entry.updatedv2.workflowTask.updated.statusv2.request.createdMinimal EventBridge rule (filter request creation by schema name):
{
"detail-type": ["v2.request.created"],
"detail": {
"schema": {
"name": ["Validated Request"]
}
}
}
Lambda handler skeleton:
def handler(event, context):
detail_type = event["detail-type"]
detail = event["detail"]
if detail.get("deprecated"):
# Alert — migrate before Benchling removes this event type
pass
if detail.get("excludedProperties"):
# Payload exceeded 256 KB; re-fetch via detail["request"]["apiURL"]
pass
if detail_type == "v2.request.created":
request_id = (detail.get("request") or {}).get("id")
# Re-fetch authoritative state — events can be late or out of order
# request = benchling.requests.get_by_id(request_id)
return {"request_id": request_id}
return {"status": "ignored", "detail_type": detail_type}
Setup flow:
https://your-tenant.benchling.com/event-subscriptionsRecovery: EventBridge deliveries are not replayed. Use the List Events API for events up to ~2 weeks old after outages.
For payload schema, CloudFormation templates, SDK list/recovery examples, and validation steps, see references/eventbridge.md.
Query historical Benchling data using SQL through the Data Warehouse.
Access Method: The Benchling Data Warehouse provides SQL access to Benchling data for analytics and reporting. Connect using standard SQL clients with provided credentials.
Common Queries:
Integration with Analysis Tools: