--- name: benchling-integration description: Benchling Python SDK and REST API integration for registry entities, inventory, ELN entries, workflows, Benchling Apps, and Data Warehouse queries. Use when automating lab data with benchling-sdk or the v2 API. license: MIT allowed-tools: Read Write Edit Bash compatibility: Requires a Benchling account, tenant URL, and API key or OAuth app credentials. Install benchling-sdk with uv pip install. metadata: version: "1.2" skill-author: K-Dense Inc. --- # Benchling Integration ## Overview Benchling is a cloud platform for life sciences R&D. Access registry entities (DNA, RNA, proteins), inventory, electronic lab notebooks, and workflows programmatically via the Python SDK and REST API. **Version note:** Examples target **benchling-sdk 1.25.0** (latest stable on PyPI). Docs: [benchling.com/sdk-docs](https://benchling.com/sdk-docs/). Platform guide: [docs.benchling.com](https://docs.benchling.com/). ## When to Use This Skill This skill should be used when: - Working with Benchling's Python SDK or REST API - Managing biological sequences (DNA, RNA, proteins) and registry entities - Automating inventory operations (samples, containers, locations, transfers) - Creating or querying electronic lab notebook entries - Building workflow automations or Benchling Apps - Syncing data between Benchling and external systems - Querying the Benchling Data Warehouse for analytics - Setting up event-driven integrations with AWS EventBridge ## Core Capabilities ### 1. Authentication & Setup **Python SDK installation:** ```bash uv pip install "benchling-sdk==1.25.0" ``` Preview builds (alpha; not for production): ```bash 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: ```python 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](https://docs.benchling.com/docs/getting-started-benchling-apps) and store `BENCHLING_CLIENT_ID` / `BENCHLING_CLIENT_SECRET` separately. **Authentication methods:** API key (scripts and personal automation): ```python 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): ```python 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:** - All API requests require HTTPS; network calls must target your tenant URL only - Authentication permissions mirror UI permissions - Verify credentials with `benchling.users.get_me()` before bulk operations For detailed authentication information including OIDC and security best practices, refer to `references/authentication.md`. ### 2. Registry & Entity Management 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:** ```python 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: ```python 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:** ```python 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:** ```python # 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:** - Create: `benchling..create()` - Read: `benchling..get_by_id(id)` or `.list()` - Update: `benchling..update(id, update_object)` - Archive: `benchling..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`. ### 3. Inventory Management Manage physical samples, containers, boxes, and locations within the Benchling inventory system. **Creating Containers:** ```python 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:** ```python 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:** ```python # Transfer a container to a new location transfer = benchling.containers.transfer( container_id="cont_abc123", destination_id="box_xyz789" ) ``` **Key Inventory Operations:** - Create containers, boxes, locations, plates - Update inventory item properties - Transfer items between locations - Check in/out items - Batch operations for bulk transfers ### 4. Notebook & Documentation Interact with electronic lab notebook (ELN) entries, protocols, and templates. **Creating Notebook Entries:** ```python 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:** ```python # Add references to entities in an entry entry_link = benchling.entry_links.create( entry_id="entry_abc123", entity_id="seq_xyz789" ) ``` **Key Notebook Operations:** - Create and update lab notebook entries - Manage entry templates - Link entities and results to entries - Export entries for documentation ### 5. Workflows & Automation Automate laboratory processes using Benchling's workflow system. **Creating Workflow Tasks:** ```python 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:** ```python 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): ```python 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:** - Create and manage workflow tasks - Update task statuses and assignments - Execute bulk operations asynchronously - Monitor task progress ### 6. Events & Integration 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.updated` - `v2.entity.registered` - `v2.entry.created`, `v2.entry.updated` - `v2.workflowTask.updated.status` - `v2.request.created` **Minimal EventBridge rule** (filter request creation by schema name): ```json { "detail-type": ["v2.request.created"], "detail": { "schema": { "name": ["Validated Request"] } } } ``` **Lambda handler skeleton:** ```python 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:** 1. Tenant admin creates a subscription at `https://your-tenant.benchling.com/event-subscriptions` 2. Associate the AWS partner event source with a dedicated event bus immediately (within ~12 days) 3. Create rules + targets (Lambda, SQS, SNS) and grant invoke permissions 4. Validate with a CloudWatch Logs rule, then trigger a matching Benchling action **Recovery:** EventBridge deliveries are not replayed. Use the [List Events API](https://benchling.com/api/reference#/Events/listEvents) 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`. ### 7. Data Warehouse & Analytics 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:** - Aggregate experimental results - Analyze inventory trends - Generate compliance reports - Export data for external analysis **Integration with Analysis Tools:** - Jupyter notebooks for interactive analysis - BI tools (Tableau, Looker, PowerBI) - Custom dashboards ## Best Practices ### Error Handling The SDK automatically retries failed requests: ```python # Automatic retry for 429, 502, 503, 504 status codes # Up to 5 retries with exponential backoff # Customize retry behavior if needed from benchling_sdk.retry import RetryStrategy benchling = Benchling( url=tenant_url, auth_method=ApiKeyAuth(api_key), retry_strategy=RetryStrategy(max_retries=3), ) ``` ### Pagination Efficiency Use generators for memory-efficient pagination: ```python # Generator-based iteration for page in benchling.dna_sequences.list(): for sequence in page: process(sequence) # Check estimated count without loading all pages total = benchling.dna_sequences.list().estimated_count() ``` ### Schema Fields Helper Use the `fields()` helper for custom schema fields: ```python # Convert dict to Fields object custom_fields = benchling.models.fields({ "concentration": "100 ng/μL", "date_prepared": "2025-10-20", "notes": "High quality prep" }) ``` ### Forward Compatibility The SDK handles unknown enum values and types gracefully: - Unknown enum values are preserved - Unrecognized polymorphic types return `UnknownType` - Allows working with newer API versions ### Security Considerations - Never commit API keys or OAuth secrets to version control - Read only named environment variables (`BENCHLING_TENANT_URL`, `BENCHLING_API_KEY`, etc.) - Route network calls exclusively to your tenant URL - Rotate keys if compromised; use OAuth for multi-user production apps - Grant minimal necessary permissions for apps in the Developer Console ## Resources ### references/ Detailed reference documentation for in-depth information: - **authentication.md** - Comprehensive authentication guide including OIDC, security best practices, and credential management - **sdk_reference.md** - Detailed Python SDK reference with advanced patterns, examples, and all entity types - **api_endpoints.md** - REST API endpoint reference for direct HTTP calls without the SDK - **eventbridge.md** - EventBridge setup, event payload schema, rule examples, Lambda handler, validation, and recovery Load these references as needed for specific integration requirements. ## Common Use Cases **1. Bulk Entity Import:** ```python # Import multiple sequences from FASTA file from Bio import SeqIO for record in SeqIO.parse("sequences.fasta", "fasta"): benchling.dna_sequences.create( DnaSequenceCreate( name=record.id, bases=str(record.seq), is_circular=False, folder_id="fld_abc123" ) ) ``` **2. Inventory Audit:** ```python # List all containers in a specific location containers = benchling.containers.list( parent_storage_id="box_abc123" ) for page in containers: for container in page: print(f"{container.name}: {container.barcode}") ``` **3. Workflow Automation:** ```python # Update all pending tasks for a workflow tasks = benchling.workflow_tasks.list( workflow_id="wf_abc123", status="pending" ) for page in tasks: for task in page: # Perform automated checks if auto_validate(task): benchling.workflow_tasks.update( task_id=task.id, workflow_task=WorkflowTaskUpdate( status_id="status_complete" ) ) ``` **4. Data Export:** ```python # Export all sequences with specific properties sequences = benchling.dna_sequences.list() export_data = [] for page in sequences: for seq in page: if seq.schema_id == "target_schema_id": export_data.append({ "id": seq.id, "name": seq.name, "bases": seq.bases, "length": len(seq.bases) }) # Save to CSV or database import csv with open("sequences.csv", "w") as f: writer = csv.DictWriter(f, fieldnames=export_data[0].keys()) writer.writeheader() writer.writerows(export_data) ``` ## Additional Resources - **Official Documentation:** https://docs.benchling.com - **Python SDK Reference:** https://benchling.com/sdk-docs/ - **API Reference:** https://benchling.com/api/reference - **Support:** [email protected]