# eb-event-delivery

Part of **EB**

<!-- intent-backlink:auto -->

> 💡 **Path Selection**: This skill is one implementation path for [Deliver events to external destinations (API/OSS/MQTT)](../../intent/eb-deliver-destinations/SKILL.md). If you're unsure which path to take, check the routing skill first.

# EventBridge Event Delivery

## Capabilities Overview

| Sub-capability | Calling Mode | Description |
|--------|----------|------|
| Create API Destination | Synchronous | Create a destination for delivering events to external HTTP endpoints. |
| Delete API Destination | Synchronous | Remove an existing API destination. |
| Get API Destination Info | Synchronous | Retrieve configuration details of an API destination. |
| List API Destinations | Synchronous | List all configured API destinations. |
| Update API Destination | Synchronous | Modify the configuration of an existing API destination. |
| Configure API Destination | Synchronous | Set up parameters for API destination delivery. |
| Deliver Events to MQTT | Synchronous | Configure MQTT as a delivery target for events. |
| Deliver Events to OSS | Synchronous | Configure OSS as a delivery target for events. |
| Configure RabbitMQ Sink | Synchronous | Set up RabbitMQ metadata parameters for event delivery. |
| Deliver Event to RabbitMQ | Synchronous | Configure RabbitMQ message sync parameters for event delivery. |
| Publish Events | Synchronous | Send custom or system events to EventBridge using the PutEvents API. |
| Verify Event Signature | Synchronous | Validate the authenticity of events delivered to HTTP/HTTPS targets. |
| Calculate Event Size | Synchronous | Determine the size of events to ensure they comply with limits. |

## API Calling Modes

### Authentication
The primary authentication method is Bearer Token authentication.

- Use the header: `Authorization: Bearer <your_api_key>`
- Store your credential in the environment variable: `DASHSCOPE_API_KEY`
- Some operations may use AccessKey-based authentication with `accessKeyId` and `accessKeySecret` in the SDK configuration, but Bearer Token is recommended for consistency.

### Service Endpoint
The base URL pattern for EventBridge APIs is region-specific:

- China regions: `https://eventbridge.{region}.aliyuncs.com`
- International regions: `https://eventbridge.global.aliyuncs.com`

Common regions include:
- `cn-hangzhou`
- `cn-shanghai`
- `cn-beijing`

For API catalog operations (e.g., CreateApiDestination), use:
- China: `https://api.aliyun.com/api/eventbridge/2020-04-01/{operation}`
- International: `https://api.alibabacloud.com/api/eventbridge/2020-04-01/{operation}`

### Synchronous API Pattern
All operations in this domain follow a synchronous calling pattern:

1. Construct the request with required parameters
2. Send the request to the appropriate endpoint with proper authentication
3. Receive an immediate JSON response with result or error details
4. Parse the response to handle success or failure cases

No asynchronous polling or streaming patterns are used in this domain.

## Parameter Reference

### Create API Destination

| Parameter | Type | Required | Default | Constraints | Description |
|------|------|------|--------|------|------|
| ApiDestinationName | string | true | null | 2 to 127 characters | The name of the API destination. |
| ConnectionName | string | true | null | 2 to 127 characters | The name of the connection. |
| Description | string | false | null | max 255 characters | The description of the API destination. |
| HttpApiParameters | object | true | null | null | The parameters that are configured for the API destination. |
| Endpoint | string | true | null | max 127 characters | The endpoint of the API destination. |
| Method | string | true | null | one of: GET, POST, HEAD, DELETE, PUT, PATCH | The HTTP request method. |

### Publish Events

| Parameter | Type | Required | Default | Constraints | Description |
|------|------|------|--------|------|------|
| events | array | true | null | null | A list of CloudEvent objects to be published. |
| datacontenttype | string | false | application/json | e.g., 'application/json', 'text/plain' | The content type of the event data. |
| data | bytes | false | null | max length depends on service limits | The payload of the event. |
| id | string | true | null | must be unique within the event bus | A unique identifier for the event. |
| source | string | true | null | null | The source of the event, typically a service or application name. |
| time | string | false | current time | ISO 8601 format with timezone | The timestamp of when the event occurred. |
| subject | string | false | null | max length 256 characters | A subject line for the event. |
| type | string | true | null | must match pattern: [a-zA-Z0-9._-]+ | The type of the event. |
| extensions | map | false | null | contains key 'aliyuneventbusname' for specifying the event bus | Additional metadata about the event. |

### Deliver Events to OSS

| Parameter | Type | Required | Default | Constraints | Description |
|------|------|------|--------|------|------|
| BucketName | string | true | null | null | Name of the destination OSS bucket. |
| RegionId | string | true | null | null | Region where the OSS bucket is located. |
| Endpoint | string | true | null | null | OSS endpoint for the bucket. Format: https://oss-{region}.aliyuncs.com. |
| RoleArn | string | true | null | null | Alibaba Cloud Resource Name (ARN) of the RAM role that EventBridge assumes to write to the bucket. |
| SSLEnabled | boolean | false | true | null | Whether to enable SSL/TLS for the connection to OSS. |
| RotateSizeBytes | string | false | null | value must be a positive integer representing bytes | Maximum file size in bytes before rotation. |
| RotateIntervalMs | string | false | null | value must be a positive integer representing milliseconds | Maximum time interval in milliseconds before rotation. |
| PathFormat | string | false | null | must use valid time placeholders like yyyy/MM/dd/HH | Path format pattern for the OSS object key. |
| CompressionType | string | false | null | one of: gzip | Compression algorithm for output files. |
| TimeZone | string | false | null | valid IANA timezone name (e.g., Asia/Shanghai) | Time zone used to resolve time-based placeholders in PathFormat. |
| TaskConcurrency | string | false | 1 | positive integer | Number of concurrent delivery tasks. |
| ContentTransform.Form | string | false | null | one of: TEMPLATE | Transformation mode. |
| ContentTransform.Value | string | false | null | valid JSONPath expression | Expression that specifies which part of the event to extract. |
| ContentTransform.Template | string | false | null | must contain valid ${} placeholders referencing fields from Value | Template string that defines the output format. |

### Configure API Destination

| Parameter | Type | Required | Default | Constraints | Description |
|------|------|------|--------|------|------|
| Name | string | false | null | null | The name of the API destination. |
| HeaderParameters | object | false | null | null | The custom HTTP header parameters to add to the request. |
| BodyParameters | object | false | null | null | The parameters for the HTTP request body. |
| QueryStringParameters | object | false | null | null | The query string parameters to add to the endpoint URL. |
| Timeout | integer | false | null | range 1-60 | The timeout for the API call, in seconds. |

## Code Examples

### Publish Events - Python - All Regions

```python
# -*- coding: utf-8 -*-

from alibabacloud_eventbridge.client import Client as EventBridgeClient
from alibabacloud_eventbridge import models as event_bridge_models
from alibabacloud_tea_console.client import Client as ConsoleClient
from alibabacloud_tea_util.client import Client as UtilClient

class put_events(object):
    def __init__(self):
        pass

    @staticmethod
    def create_client():
        """
        Uses the create_client() function to initialize common request parameters.
        """
        config = event_bridge_models.Config(

        )
        # Your AccessKey ID.
        config.access_key_id = "<accessKeyId>"
        # Your AccessKey secret.
        config.access_key_secret = "<accessKeySecret>"
        # Your endpoint.
        config.endpoint = "<endpoint>"
        return EventBridgeClient(config)

    @staticmethod
    def put_events(client):
        """
        PutEvents
        """
        event = event_bridge_models.CloudEvent(

        )
        event.datacontenttype = "application/json"
        event.data = UtilClient.to_bytes("test")
        event.id = "a5074581-7e74-4e4c-868f-47e7afdf****"
        event.source = "acs.oss"
        event.specversion = "1.0"
        event.type = "oss:ObjectCreated:PostObject"
        event.time = "2020-08-24T13:54:05.965Asia/Shanghai"
        event.subject = "acs:oss:cn-hangzhou:1234567:xls-papk/game_apk/123.jpg"
        event.extensions = {
            "aliyuneventbusname": "demo-bus"
        }
        try:
            resp = client.put_events([
                event
            ])
            ConsoleClient.log("--------------------Publish event to the aliyun EventBus--------------------")
            ConsoleClient.log(UtilClient.to_jsonstring(resp.to_map()))
        except Exception as error:
            ConsoleClient.log(error.message)

    @staticmethod
    def main(args):
        client = put_events.create_client()
        put_events.put_events(client)

put_events.main("")
```

### Verify Event Signature - Python - All Regions

```python
import base64
import hashlib
import hmac
import time
import urllib.request

from cryptography import x509

def verify_eventbridge_signature(headers, url, body):
    """Verify an EventBridge HTTP push request signature.

    Args:
        headers: Dict of HTTP request headers.
        url: Full request URL including query string.
        body: Raw request body as bytes (UTF-8).

    Returns:
        True if the signature is valid, False otherwise.
    """
    # Step 1: Check timestamp (60-second tolerance)
    timestamp = int(headers["x-eventbridge-signature-timestamp"])
    now_ms = int(time.time() * 1000)
    if abs(now_ms - timestamp) > 60000:
        return False

    # Step 2: Validate certificate URL
    cert_url = headers["x-eventbridge-signature-url"]
    if not cert_url.startswith("https://") or \
       not cert_url.endswith("-eventbridge.oss-accelerate.aliyuncs.com"):
        return False

    # Step 3: Download certificate and decrypt temporary secret
    cert_pem = urllib.request.urlopen(cert_url).read()
    cert = x509.load_pem_x509_certificate(cert_pem)
    public_key = cert.public_key()

    encrypted_secret = base64.b64decode(
        headers["x-eventbridge-signature-secret"]
    )
    # Use the public key to decrypt the temporary secret.
    # RSA public-key decryption is the inverse of private-key encryption.
    # The cryptography library does not expose public-key decrypt directly,
    # so we perform raw RSA (modular exponentiation) and strip PKCS#1 v1.5 padding.
    pub_numbers = public_key.public_numbers()
    cipher_int = int.from_bytes(encrypted_secret, "big")
    plain_int = pow(cipher_int, pub_numbers.e, pub_numbers.n)
    key_len = (pub_numbers.n.bit_length() + 7) // 8
    padded = plain_int.to_bytes(key_len, "big")
    # PKCS#1 v1.5 type 1 padding: 0x00 0x01 <0xFF bytes> 0x00 <data>
    separator = padded.index(b"\x00", 2)
    temp_secret = padded[separator + 1:]

    # Step 4: Build string-to-sign
    string_to_sign = url + "\n"
    string_to_sign += "x-eventbridge-signature-timestamp: " + headers["x-eventbridge-signature-timestamp"] + "\n"
    string_to_sign += "x-eventbridge-signature-method: " + headers["x-eventbridge-signature-method"] + "\n"
    string_to_sign += "x-eventbridge-signature-version: " + headers["x-eventbridge-signature-version"] + "\n"
    string_to_sign += "x-eventbridge-signature-url: " + cert_url

    if "x-eventbridge-signature-token" in headers:
        string_to_sign += "\n" + "x-eventbridge-signature-token: " + headers["x-eventbridge-signature-token"]

    string_to_sign += "\n" + body

    # Step 5: Compute and compare signature (constant-time)
    computed = base64.b64encode(
        hmac.new(temp_secret, string_to_sign.encode("utf-8"), hashlib.sha1).digest()
    ).decode("utf-8")

    return hmac.compare_digest(computed, headers["x-eventbridge-signature"])
```

### Deliver Events to OSS - JSON - All Regions

```json
{
  "BucketName": "my-event-logs",
  "RegionId": "cn-hangzhou",
  "Endpoint": "https://oss-cn-hangzhou.aliyuncs.com",
  "RoleArn": "acs:ram::123456789:role/eventbridge-oss-role",
  "SSLEnabled": true,
  "RotateSizeBytes": "67108864",
  "RotateIntervalMs": "3600000",
  "PathFormat": "yyyy/MM/dd/HH",
  "CompressionType": "gzip",
  "TimeZone": "Asia/Shanghai",
  "TaskConcurrency": "1",
  "ContentTransform": {
    "Form": "TEMPLATE",
    "Value": "$.data",
    "Template": "The event ${eventName} occurred at ${time}"
  }
}
```

### Deliver Events to MQTT - JSON - All Regions

```json
{
  "Id": "mqtt-target-1",
  "Type": "acs.mqtt",
  "SinkMQTTParameters": {
    "InstanceId": "mqtt-cn-xxxx",
    "ParentTopic": "deviceTelemetry",
    "SubTopic": {
      "Form": "TEMPLATE",
      "Value": "{\"deviceType\": \"$.data.type\", \"deviceId\": \"$.data.id\"}",
      "Template": "/${deviceType}/${deviceId}"
    },
    "Payload": {
      "Form": "JSONPATH",
      "Value": "$.data"
    },
    "Mqtt5UserProperty": {
      "Form": "CONSTANT",
      "Value": "[{\"key\": \"source\", \"value\": \"eventbridge\"}, {\"key\": \"version\", \"value\": \"1.0\"}]"
    }
  }
}
```

### Publish Events - Java - All Regions

```java
import com.aliyun.eventbridge.EventBridge;
import com.aliyun.eventbridge.EventBridgeClient;
import com.aliyun.eventbridge.models.CloudEvent;
import com.aliyun.eventbridge.models.Config;
import com.aliyun.eventbridge.models.PutEventsResponse;
import com.aliyun.eventbridge.util.EventBuilder;
import com.google.gson.Gson;

import java.net.URI;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class PutEventsSample {

    private EventBridge eventBridgeClient;

    public PutEventsSample() {
        Config authConfig = new Config();
        authConfig.accessKeyId = "{accessKeyId}";// The AccessKey ID for identity authentication. You can create AccessKey IDs in the RAM console. For more information about how to obtain the ID, see Obtain an AccessKey pair.  
        authConfig.accessKeySecret = "{accessKeySecret}";// The AccessKey secret for identity authentication. You can create AccessKey secrets in the RAM console. For more information about how to obtain the ID, see Obtain an AccessKey pair. 
        authConfig.endpoint = "{endpoint}";// The endpoint. For more information, see Regions and endpoints. 
        eventBridgeClient = new EventBridgeClient(authConfig);
    }

    public void putEventsSample() {
        List<CloudEvent> cloudEventList = new ArrayList<>();
        cloudEventList.add(EventBuilder.builder()
                .withId("a5074581-7e74-4e4c-868f-47e7afdf****")
                .withSource(URI.create("acs.oss"))
                .withType("oss:ObjectCreated:PostObject")
                .withSubject("acs:oss:cn-hangzhou:{yourAccountId}:xls-papk/game_apk/123.jpg")
                .withTime(new Date())
                .withJsonStringData("{ \"E-Mail\": \"${email}\" }")
                .withAliyunEventBus("demo-bus")
                .build());
        PutEventsResponse putEventsResponse = eventBridgeClient.putEvents(cloudEventList);
        System.out.println(new Gson().toJson(putEventsResponse));
    }

    public static void main(String[] args){
        PutEventsSample sample = new PutEventsSample();
        try {
            sample.putEventsSample();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}
```

### Configure RabbitMQ Sink - JSON - All Regions

```json
{
  "InstanceType": "<instance-type>",
  "InstanceId": "amqp-cn-******",
  "Endpoint": "amqp-cn-******.mq-amqp.cn-hangzhou-a.aliyuncs.com",
  "VirtualHostName": "/",
  "Username": "<username>",
  "Password": "<password>",
  "NetworkType": "PrivateNetwork",
  "VpcId": "<vpc-id>",
  "VSwitchIds": "<vswitch-id>",
  "SecurityGroupId": "<security-group-id>"
}
```

## Response Format

```json
{
  "RequestId": "5DAF96FB-A4B6-548C-B999-0BFDCB22****",
  "Message": "success",
  "Code": "Success",
  "Date": {
    "ApiDestinationName": "ApiDestinationName"
  }
}
```

**Key Fields**:
- `RequestId` — Unique identifier for the API request
- `Message` — Human-readable status message
- `Code` — Status code indicating success or failure
- `Date.ApiDestinationName` — Name of the created API destination

## Error Handling

| Error Code (Code) | Description (Description) | Recommended Action (Recommended Action) |
|---------------|--------------------|-----------------------------|
| 500 | InternalError — An internal server error occurred. | Retry the request or contact support if the issue persists. |
| 409 | RequestParameterException — A request parameter is invalid or missing. | Verify all required parameters are correctly provided and formatted. |
| 409 | RequestParameterInvalid — The ApiDestination name is invalid! Only letters a~z or A~Z, numbers 0~9, underscore (_) and dash (-) are supported. | Ensure the API destination name follows the allowed character set. |
| 409 | ApiDestinationAlreadyExist — The API destination already exists. | Use a different name or delete the existing destination first. |
| 409 | ConnectionNotExist — The specified connection does not exist. | Create the connection first using CreateConnection operation. |
| 409 | HttpApiParametersIsNull — HttpApiParameters is null! | Provide valid HttpApiParameters in your request. |
| 409 | EndpointIsBlank — Endpoint is blank! | Specify a valid endpoint URL. |
| 409 | Method — Method is blank! | Specify a valid HTTP method (GET, POST, etc.). |
| 409 | EndpointLengthExceed — Endpoint length cannot exceed 127! | Shorten your endpoint URL to meet the length requirement. |
| 409 | ApiDestinationCountExceedLimit — The current count of API destinations has exceeded the quota limit. | Delete unused API destinations or request a quota increase. |
| 409 | ApiDestinationNotExist - The specified API destination does not exist. | Ensure the destination name is correct and the resource exists. |
| 400 | Invalid request body. Check that all required parameters are present and correctly formatted. | Verify your request body matches the expected schema. |
| 403 | Access denied. Verify that the RoleArn has sufficient permissions to write to the target OSS bucket. | Update the RAM role permissions to allow OSS write access. |
| 404 | Bucket not found. Confirm that the BucketName and RegionId are correct. | Double-check the bucket name and region configuration. |

### Rate Limits & Retry
- Standard rate limit: 100 QPS per account
- OSS delivery: maximum 10 requests per second
- When encountering rate limit errors (429/Throttling), implement exponential backoff with jitter
- For transient errors (5xx), retry with a short delay (1-5 seconds)
- Failed deliveries may still incur charges, so monitor delivery success rates

## Environment Requirements

- Python: `pip install alibabacloud_eventbridge>=1.0.0 alibabacloud_tea_console>=1.0.0 alibabacloud_tea_util>=1.0.0`
- Java: `aliyun-eventbridge-sdk>=1.0.0`
- Go: `github.com/alibabacloud-go/eventbridge-sdk@v1.0.0 or later`
- PHP: `AlibabaCloud/SDK:EventBridge>=1.0.0`
- TypeScript/JavaScript: `npm install @alicloud/eventbridge tea-util tea-console tea-typescript`
- Set environment variable: `export DASHSCOPE_API_KEY=your_api_key`

## FAQ

Q: How do I authenticate my EventBridge API requests?
A: Use Bearer Token authentication with the header `Authorization: Bearer <your_api_key>`. Store your API key in the `DASHSCOPE_API_KEY` environment variable for security.

Q: What is the maximum size for events published via PutEvents?
A: The total request size must not exceed 256 KB. This includes all event attributes and payload data. Calculate event size by measuring UTF-8 byte lengths of string attributes plus raw byte length of the data payload.

Q: How can I verify that events delivered to my HTTP endpoint are authentic?
A: Implement signature verification using the provided code examples. EventBridge signs requests with RSA-SHA256 and includes headers like `x-eventbridge-signature`, `x-eventbridge-signature-timestamp`, and `x-eventbridge-signature-url` that you must validate.

Q: What delivery targets are supported by EventBridge?
A: EventBridge supports multiple delivery targets including HTTP/HTTPS endpoints (API destinations), OSS buckets, MQTT topics, and RabbitMQ queues. Each target type has specific configuration parameters documented in the API reference.

Q: How are API destinations different from regular HTTP targets?
A: API destinations are reusable configurations that define external HTTP endpoints with connection settings, authentication, and parameter mappings. They can be referenced by multiple event rules, providing centralized management of external integrations.

## Pricing & Billing

### Billing Model
Per-request billing model where each API call or event delivery attempt is counted as one request.

### Price Reference

| Tier/Specification | Input Price | Output Price |
|-----------|---------|---------|
| default | 0.0001 / | 0.0001 / |
| Standard | 0.0001 / | 0.0001 / |

### Free Tier
- Monthly free allowance of 1,000 requests for most operations
- Some operations (like DeleteApiDestination) offer 10,000 free requests per month

### Usage Limits
- Account-level rate limit of 100 QPS
- Single request maximum of 100 events for PutEvents
- API destination timeout range: 1-60 seconds
- Single request size limit: 256 KB

### Billing Notes
- Charges apply per request regardless of success or failure for most operations
- API destination calls that time out do not incur charges
- Free tier resets monthly on the 1st
- Each event published via PutEvents counts as one request, even when batching multiple events