Skill Tracer
Skills › Scientific Agent Skills › benchling-integration › eventbridge.md

eventbridge.md

275 lines · skills/benchling-integration/references/eventbridge.md at 5f2bc03

Open on GitHub
1# Benchling Events via AWS EventBridge
2
3Integrations that react to supported Benchling changes, including entity registration and
4workflow updates. Reviewed 2026-09-30. Payloads and AWS deployment snippets are illustrative;
5no tenant subscription or deployment was tested. Event names below were checked against
6the current EventBridge reference and SDK 1.25.0 event models.
7
8**Official docs:**
9- [Getting Started with Events](https://docs.benchling.com/docs/events-getting-started)
10- [Events Reference (payloads and event types)](https://docs.benchling.com/docs/events-reference)
11- [Events FAQs](https://docs.benchling.com/docs/events-faqs)
12- [List Events API](https://benchling.com/api/reference#/Events/listEvents)
14**Delivery methods:** Benchling supports **Webhooks** (recommended for new apps) and **AWS EventBridge** (customer-owned event bus). EventBridge payloads are **hydrated** (full v2 API objects in `detail`); webhooks use thinner payloads. See the getting-started guide for trade-offs.
16---

Benchling Events via AWS EventBridge

Integrations that react to supported Benchling changes, including entity registration and workflow updates. Reviewed 2026-09-30. Payloads and AWS deployment snippets are illustrative; no tenant subscription or deployment was tested. Event names below were checked against the current EventBridge reference and SDK 1.25.0 event models.

Official docs:

Delivery methods: Benchling supports Webhooks (recommended for new apps) and AWS EventBridge (customer-owned event bus). EventBridge payloads are hydrated (full v2 API objects in detail); webhooks use thinner payloads. See the getting-started guide for trade-offs.


Raw lines 1 to 17
18## Setup checklist
201. **Tenant admin** enables Developer Platform access and opens [Event Subscriptions](https://your-tenant.benchling.com/event-subscriptions) (Feature settings → Developer Console → Events).
212. Create a subscription with:
22 - AWS account ID and region
23 - Event bus name (e.g. `benchling-integrations`)
24 - Event types to receive (see [Events Reference](https://docs.benchling.com/docs/events-reference))
253. **Immediately** associate the partner event source with a new EventBridge bus in AWS (within ~12 days or the source expires).
264. Create EventBridge rules with `detail-type` / `detail` filters and targets (Lambda, SQS, SNS, CloudWatch Logs).
275. Grant invoke permissions (`AWS::Lambda::Permission`, queue policies, etc.).
286. Validate with a CloudWatch Logs rule on the bus `source`, then trigger a test action in Benchling.
30Subscription statuses: `Pending` (needs bus association), `Active`, `Expired` (resubscribe in Benchling).
32---

Setup checklist

  1. Tenant admin enables Developer Platform access and opens Event Subscriptions (Feature settings → Developer Console → Events).
  2. Create a subscription with:
  3. AWS account ID and region
  4. Event bus name (e.g. benchling-integrations)
  5. Event types to receive (see Events Reference)
  6. Immediately associate the partner event source with a new EventBridge bus in AWS (within ~12 days or the source expires).
  7. Create EventBridge rules with detail-type / detail filters and targets (Lambda, SQS, SNS, CloudWatch Logs).
  8. Grant invoke permissions (AWS::Lambda::Permission, queue policies, etc.).
  9. Validate with a CloudWatch Logs rule on the bus source, then trigger a test action in Benchling.

Subscription statuses: Pending (needs bus association), Active, Expired (resubscribe in Benchling).


Raw lines 18 to 33
34## EventBridge event envelope
36All EventBridge deliveries share this top-level shape. The resource body lives under `detail` under a key that varies by event (for example `entry`, `assayRun`, `request`).
38```json
40 "version": "0",
41 "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
42 "detail-type": "v2.request.created",
43 "source": "aws.partner/benchling.com/your-tenant/your-subscription-name",
44 "account": "123456789012",
45 "time": "2026-09-29T14:30:00.000000+00:00",
46 "region": "us-west-2",
47 "resources": [],
48 "detail": {
49 "id": "evt_abc123",
50 "eventType": "v2.request.created",
51 "createdAt": "2026-09-29T14:30:00.000000+00:00",
52 "deprecated": false,
53 "excludedProperties": [],
54 "schema": {
55 "id": "ts_abc123",
56 "name": "Validated Request"
57 },
58 "request": {
59 "id": "req_example",
60 "name": "Sequencing request",
61 "apiURL": "https://your-tenant.benchling.com/api/v2/requests/req_example"
62 }
63 }
65```
67**Naming:** `detail-type` and `detail.eventType` follow `<version>.<resource>.<action>` (for example `v2.request.created`, `v2.workflowTask.updated.status`).
69**Do not treat payloads as authoritative.** Events may arrive late or out of order. Re-fetch objects with the SDK/API when you need current state.
71**Truncated events:** Benchling documents a 256 KB EventBridge payload threshold.
72Inspect `detail.excludedProperties`. Re-fetch by ID through the configured tenant SDK;
73do not send credentials to an arbitrary `apiURL` from an event.
75---

EventBridge event envelope

All EventBridge deliveries share this top-level shape. The resource body lives under detail under a key that varies by event (for example entry, assayRun, request).

{
  "version": "0",
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "detail-type": "v2.request.created",
  "source": "aws.partner/benchling.com/your-tenant/your-subscription-name",
  "account": "123456789012",
  "time": "2026-09-29T14:30:00.000000+00:00",
  "region": "us-west-2",
  "resources": [],
  "detail": {
    "id": "evt_abc123",
    "eventType": "v2.request.created",
    "createdAt": "2026-09-29T14:30:00.000000+00:00",
    "deprecated": false,
    "excludedProperties": [],
    "schema": {
      "id": "ts_abc123",
      "name": "Validated Request"
    },
    "request": {
      "id": "req_example",
      "name": "Sequencing request",
      "apiURL": "https://your-tenant.benchling.com/api/v2/requests/req_example"
    }
  }
}

Naming: detail-type and detail.eventType follow <version>.<resource>.<action> (for example v2.request.created, v2.workflowTask.updated.status).

Do not treat payloads as authoritative. Events may arrive late or out of order. Re-fetch objects with the SDK/API when you need current state.

Truncated events: Benchling documents a 256 KB EventBridge payload threshold. Inspect detail.excludedProperties. Re-fetch by ID through the configured tenant SDK; do not send credentials to an arbitrary apiURL from an event.


Raw lines 34 to 76
77## Minimal EventBridge rule (CloudFormation)
79Route `v2.request.created` events for a specific request schema to a Lambda:
81```yaml
82AWSTemplateFormatVersion: "2010-09-09"
83Transform: AWS::Serverless-2016-10-31
84Description: Benchling request.created → Lambda
86Parameters:
87 BenchlingEventBusName:
88 Type: String
89 Description: Partner event bus name from Benchling subscription
91Resources:
92 RequestCreatedRule:
93 Type: AWS::Events::Rule
94 Properties:
95 Name: benchling-request-created
96 EventBusName: !Ref BenchlingEventBusName
97 State: ENABLED
98 EventPattern:
99 detail-type:
100 - v2.request.created
101 detail:
102 schema:
103 name:
104 - Validated Request
105 Targets:
106 - Id: HandleRequestCreated
107 Arn: !GetAtt HandleEventLambda.Arn
109 HandleEventLambda:
110 Type: AWS::Serverless::Function
111 Properties:
112 Handler: app.handler
113 Runtime: python3.12
114 CodeUri: src/
115 Timeout: 30
117 AllowEventBridgeInvoke:
118 Type: AWS::Lambda::Permission
119 Properties:
120 Action: lambda:InvokeFunction
121 FunctionName: !Ref HandleEventLambda
122 Principal: events.amazonaws.com
123 SourceArn: !GetAtt RequestCreatedRule.Arn
124```
126**Other filter examples** (from Benchling docs):
128```json
130 "detail-type": ["v2.assayRun.updated.fields"],
131 "detail": {
132 "updates": ["fields.my_field"]
133 }
135```
137```json
139 "detail-type": ["v2.entity.registered"],
140 "detail": {
141 "entity": {
142 "schema": {
143 "id": ["ts_MySchemaId"]
144 }
145 }
146 }
148```
150---

Minimal EventBridge rule (CloudFormation)

Route v2.request.created events for a specific request schema to a Lambda:

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Benchling request.created → Lambda

Parameters:
  BenchlingEventBusName:
    Type: String
    Description: Partner event bus name from Benchling subscription

Resources:
  RequestCreatedRule:
    Type: AWS::Events::Rule
    Properties:
      Name: benchling-request-created
      EventBusName: !Ref BenchlingEventBusName
      State: ENABLED
      EventPattern:
        detail-type:
          - v2.request.created
        detail:
          schema:
            name:
              - Validated Request
      Targets:
        - Id: HandleRequestCreated
          Arn: !GetAtt HandleEventLambda.Arn

  HandleEventLambda:
    Type: AWS::Serverless::Function
    Properties:
      Handler: app.handler
      Runtime: python3.12
      CodeUri: src/
      Timeout: 30

  AllowEventBridgeInvoke:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref HandleEventLambda
      Principal: events.amazonaws.com
      SourceArn: !GetAtt RequestCreatedRule.Arn

Other filter examples (from Benchling docs):

{
  "detail-type": ["v2.assayRun.updated.fields"],
  "detail": {
    "updates": ["fields.my_field"]
  }
}
{
  "detail-type": ["v2.entity.registered"],
  "detail": {
    "entity": {
      "schema": {
        "id": ["ts_MySchemaId"]
      }
    }
  }
}

Raw lines 77 to 151
152## Lambda handler skeleton (Python)
154```python
155import logging
157logger = logging.getLogger()
158logger.setLevel(logging.INFO)
160# Optional: re-fetch via SDK when payload may be stale or truncated
161# import os
162# from benchling_sdk.benchling import Benchling
163# from benchling_sdk.auth.api_key_auth import ApiKeyAuth
165# benchling = Benchling(
166# url=os.environ["BENCHLING_TENANT_URL"],
167# auth_method=ApiKeyAuth(os.environ["BENCHLING_API_KEY"]),
168# )
171def handler(event, context):
172 """Process a single Benchling EventBridge delivery."""
173 detail_type = event.get("detail-type")
174 detail = event.get("detail") or {}
176 logger.info(
177 "benchling_event",
178 extra={
179 "detail_type": detail_type,
180 "event_id": detail.get("id"),
181 "benchling_event_type": detail.get("eventType"),
182 },
183 )
185 if detail.get("deprecated"):
186 logger.warning("deprecated_event_type: %s", detail_type)
188 if detail.get("excludedProperties"):
189 logger.warning(
190 "truncated_payload excluded=%s", detail.get("excludedProperties")
191 )
193 if detail_type == "v2.request.created":
194 request = detail.get("request") or {}
195 request_id = request.get("id")
196 if not request_id:
197 raise ValueError("missing request.id in event detail")
198 # Prefer API lookup for authoritative data:
199 # current = benchling.requests.get_by_id(request_id)
200 return {"status": "observed", "request_id": request_id}
202 if detail_type == "v2.workflowTask.updated.status":
203 task = detail.get("workflowTask") or {}
204 return {"status": "ok", "task_id": task.get("id")}
206 logger.info("no_handler_for_detail_type: %s", detail_type)
207 return {"status": "ignored", "detail_type": detail_type}
208```
210This skeleton only validates/routes a payload. Add persistent deduplication keyed by
211`detail.id` before side effects: delivery is at least once and can be out of order. Mark
212an event complete only after processing succeeds. Configure retries and a dead-letter
213queue; do not rely on a Lambda return value to acknowledge a business operation.
215For serverless timeouts, `benchling.tasks.wait_for_task` defaults to 600 seconds. Use a
216shorter explicit deadline or enqueue work; a server-side job continues after polling times out.
218---

Lambda handler skeleton (Python)

import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

# Optional: re-fetch via SDK when payload may be stale or truncated
# import os
# from benchling_sdk.benchling import Benchling
# from benchling_sdk.auth.api_key_auth import ApiKeyAuth
#
# benchling = Benchling(
#     url=os.environ["BENCHLING_TENANT_URL"],
#     auth_method=ApiKeyAuth(os.environ["BENCHLING_API_KEY"]),
# )


def handler(event, context):
    """Process a single Benchling EventBridge delivery."""
    detail_type = event.get("detail-type")
    detail = event.get("detail") or {}

    logger.info(
        "benchling_event",
        extra={
            "detail_type": detail_type,
            "event_id": detail.get("id"),
            "benchling_event_type": detail.get("eventType"),
        },
    )

    if detail.get("deprecated"):
        logger.warning("deprecated_event_type: %s", detail_type)

    if detail.get("excludedProperties"):
        logger.warning(
            "truncated_payload excluded=%s", detail.get("excludedProperties")
        )

    if detail_type == "v2.request.created":
        request = detail.get("request") or {}
        request_id = request.get("id")
        if not request_id:
            raise ValueError("missing request.id in event detail")
        # Prefer API lookup for authoritative data:
        # current = benchling.requests.get_by_id(request_id)
        return {"status": "observed", "request_id": request_id}

    if detail_type == "v2.workflowTask.updated.status":
        task = detail.get("workflowTask") or {}
        return {"status": "ok", "task_id": task.get("id")}

    logger.info("no_handler_for_detail_type: %s", detail_type)
    return {"status": "ignored", "detail_type": detail_type}

This skeleton only validates/routes a payload. Add persistent deduplication keyed by detail.id before side effects: delivery is at least once and can be out of order. Mark an event complete only after processing succeeds. Configure retries and a dead-letter queue; do not rely on a Lambda return value to acknowledge a business operation.

For serverless timeouts, benchling.tasks.wait_for_task defaults to 600 seconds. Use a shorter explicit deadline or enqueue work; a server-side job continues after polling times out.


Raw lines 152 to 219
220## Validation steps
2221. **Subscription active:** In Benchling, subscription status is `Active` (not `Pending` or `Expired`).
2232. **Partner source associated:** In AWS EventBridge → Partner event sources, source is associated with your bus.
2243. **Log all events:** Add a catch-all rule targeting a CloudWatch log group, filtering on your bus `source` (shown in Benchling subscription UI).
2254. **Trigger a test event:** Create or update an object matching your rule filter (for example register a DNA sequence).
2265. **Inspect logs:** Confirm `detail-type`, `detail.id`, and resource IDs match expectations.
2276. **Re-fetch check:** Call the SDK/API for the resource ID and confirm it matches your integration logic.
229---

Validation steps

  1. Subscription active: In Benchling, subscription status is Active (not Pending or Expired).
  2. Partner source associated: In AWS EventBridge → Partner event sources, source is associated with your bus.
  3. Log all events: Add a catch-all rule targeting a CloudWatch log group, filtering on your bus source (shown in Benchling subscription UI).
  4. Trigger a test event: Create or update an object matching your rule filter (for example register a DNA sequence).
  5. Inspect logs: Confirm detail-type, detail.id, and resource IDs match expectations.
  6. Re-fetch check: Call the SDK/API for the resource ID and confirm it matches your integration logic.

Raw lines 220 to 230
231## Recovering missed events
233Benchling does **not** replay EventBridge deliveries. After an outage:
2351. Get the affected time window from Benchling support.
2362. List historical events with the [List Events API](https://benchling.com/api/reference#/Events/listEvents) (retained ~2 weeks).
2373. Re-route recovered events through your own infrastructure.
239SDK 1.25.0 example (`created_atgte` is the actual parameter spelling):
241```python
242events = benchling.events.list(
243 created_atgte="2026-09-29T00:00:00+00:00",
244 event_types="v2.request.created",
247for page in events:
248 for evt in page:
249 print(evt.event_type, evt.id)
250```
252Events are ordered by processing order, not `createdAt`. Persist `starting_after`
253checkpoints only after successful processing and deduplicate overlapping recovery
254windows. Historical API results are event objects, not AWS envelopes; if feeding the
255handler above, explicitly adapt them to its `detail` and `detail-type` structure.
257---

Recovering missed events

Benchling does not replay EventBridge deliveries. After an outage:

  1. Get the affected time window from Benchling support.
  2. List historical events with the List Events API (retained ~2 weeks).
  3. Re-route recovered events through your own infrastructure.

SDK 1.25.0 example (created_atgte is the actual parameter spelling):

events = benchling.events.list(
    created_atgte="2026-09-29T00:00:00+00:00",
    event_types="v2.request.created",
)

for page in events:
    for evt in page:
        print(evt.event_type, evt.id)

Events are ordered by processing order, not createdAt. Persist starting_after checkpoints only after successful processing and deduplicate overlapping recovery windows. Historical API results are event objects, not AWS envelopes; if feeding the handler above, explicitly adapt them to its detail and detail-type structure.


Raw lines 231 to 258
259## EventBridge vs Webhooks
261| | EventBridge | Webhooks |
262|---|-------------|----------|
263| Setup | Benchling console + AWS bus/rules | Benchling App configuration |
264| Payload | Hydrated v2 API objects | Thin IDs + metadata |
265| Filtering | EventBridge `EventPattern` | App code |
266| Permissions | Not permissioned at delivery | Inherited from app |
268For new Benchling Apps, Benchling recommends **webhooks** unless you already standardize on EventBridge in AWS. See [Getting Started with Webhooks](https://docs.benchling.com/docs/getting-started-with-webhooks).
270Do not assume event names are interchangeable between delivery mechanisms. Stable
271EventBridge uses `v2.entry.updated.fields`, not a generic `v2.entry.updated`; the current
272EventBridge reference does not list `v2.dnaSequence.created` or `v2.dnaSequence.updated`.
273For entity registration use `v2.entity.registered` and its `entity` payload. For webhooks,
274verify the signature and app-specific payload against the separate
275[webhook reference](https://benchling.com/webhooks/reference).

EventBridge vs Webhooks

EventBridgeWebhooks
SetupBenchling console + AWS bus/rulesBenchling App configuration
PayloadHydrated v2 API objectsThin IDs + metadata
FilteringEventBridge EventPatternApp code
PermissionsNot permissioned at deliveryInherited from app

For new Benchling Apps, Benchling recommends webhooks unless you already standardize on EventBridge in AWS. See Getting Started with Webhooks.

Do not assume event names are interchangeable between delivery mechanisms. Stable EventBridge uses v2.entry.updated.fields, not a generic v2.entry.updated; the current EventBridge reference does not list v2.dnaSequence.created or v2.dnaSequence.updated. For entity registration use v2.entity.registered and its entity payload. For webhooks, verify the signature and app-specific payload against the separate webhook reference.

Raw lines 259 to 275