# Triggering Deployed Workflows
Source: https://docs.chain.link/cre/guides/workflow/using-triggers/http-trigger/triggering-deployed-workflows
Last Updated: 2025-11-10


Once you've [deployed a workflow](/cre/guides/operations/deploying-workflows) with an HTTP trigger, you can execute it by sending authenticated HTTP requests to the CRE gateway. This guide explains how to trigger deployed workflows in production.

## What you'll learn

This guide covers the complete technical specification for triggering deployed workflows:

- **Request format** - The JSON-RPC structure for workflow execution requests
- **JWT authentication** - How to generate cryptographically signed tokens
- **Signature process** - The ECDSA signing steps for Ethereum-compatible authentication
- **Reference implementations** - Code examples in Go and TypeScript

> **NOTE: Just testing?**
>
> If you're testing deployed workflows during development, the [Local Testing
> Tool](/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool) is much simpler—it handles all JWT
> generation automatically. This guide is for production implementations where you need full control over the HTTP
> requests.

## Prerequisites

- **Deployed workflow**: Your workflow must be deployed with an HTTP trigger. See [Deploying Workflows](/cre/guides/operations/deploying-workflows).
- **Workflow ID**: Available from deployment output or the [CRE UI](/cre/guides/operations/monitoring-workflows).
- **Private key**: The private key corresponding to one of the `authorizedKeys` configured in your HTTP trigger.

> **NOTE: For easier testing**
>
> If you're testing your deployed workflow during development, consider using the [Local Testing
> Tool](/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool) instead. It handles JWT generation
> automatically and triggers the workflow for you.

## Finding your workflow ID

Your workflow ID is a 64-character hexadecimal string (without `0x` prefix) that uniquely identifies your deployed workflow.

### From deployment output

When you deploy a workflow, the CLI displays the workflow ID:

```bash
$ cre workflow deploy my-workflow --target production-settings

...
Details:
   Workflow ID:    a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890
...
```

### From the CRE UI

1. Log in to <a href="https://app.chain.link/cre/workflows" target="_blank" rel="noopener noreferrer">app.chain.link/cre/workflows</a>
2. Click on your workflow name
3. In the **Overview** section, find the **Workflow ID** field
4. Click the copy button to copy it to your clipboard

## Request format

All workflow executions use JSON-RPC 2.0 format:

```http
POST https://01.gateway.zone-a.cre.chain.link
Content-Type: application/json
Authorization: Bearer <JWT_TOKEN>

{
  "id": "unique-request-id",
  "jsonrpc": "2.0",
  "method": "workflows.execute",
  "params": {
    "input": {
      "key1": "value1",
      "key2": "value2"
    },
    "workflow": {
      "workflowID": "your-64-character-workflow-id"
    }
  }
}
```

### Request components

| Field                        | Description                                                        |
| ---------------------------- | ------------------------------------------------------------------ |
| `jsonrpc`                    | Always `"2.0"` (JSON-RPC version)                                  |
| `id`                         | Unique identifier for this request (any string, used for tracking) |
| `method`                     | Always `"workflows.execute"`                                       |
| `params.input`               | Your custom JSON payload (passed to your workflow callback)        |
| `params.workflow.workflowID` | Your 64-character workflow ID (no `0x` prefix)                     |

> **TIP: Request ID for tracking**
>
> The `id` field helps you correlate requests with responses. Use a UUID or timestamp-based identifier for easier
> debugging and request tracking.

## JWT authentication

The `Authorization` header must contain a Bearer JWT (JSON Web Token) that proves the request was signed by an authorized key. The JWT has three parts: `header.payload.signature`.

### JWT structure

The JWT is a base64url-encoded string consisting of three parts separated by dots:

```
<base64url(header)>.<base64url(payload)>.<base64url(signature)>
```

### 1. Header

The JWT header specifies the signing algorithm:

```json
{
  "alg": "ETH",
  "typ": "JWT"
}
```

Base64url-encode this JSON to create the header part.

### 2. Payload

The JWT payload contains request metadata and a digest of the request body:

```json
{
  "digest": "0x<sha256_hash_of_request_body>",
  "iss": "0xYourEVMAddress",
  "iat": 1762807282,
  "exp": 1762807582,
  "jti": "550e8400-e29b-41d4-a716-446655440000"
}
```

**Payload fields:**

| Field    | Description                                                                  |
| -------- | ---------------------------------------------------------------------------- |
| `digest` | SHA256 hash of the JSON-RPC request body (with `0x` prefix)                  |
| `iss`    | Issuer - your EVM address (the public key corresponding to your private key) |
| `iat`    | Issued at time (Unix timestamp in seconds)                                   |
| `exp`    | Expiration time (Unix timestamp, **max 5 minutes** after `iat`)              |
| `jti`    | JWT ID (UUID v4 for replay protection)                                       |

#### Computing the digest

The `digest` is a SHA256 hash of your JSON-RPC request body **serialized as UTF-8 encoded JSON in ascending lexicographic order** (sorted by key names):

**Original request:**

```json
{
  "jsonrpc": "2.0",
  "id": "req-123",
  "method": "workflows.execute",
  "params": {
    "input": { "key1": "value1", "key2": "value2" },
    "workflow": { "workflowID": "a1b2c3..." }
  }
}
```

**Keys must be sorted alphabetically at every level:**

```json
{
  "id": "req-123",
  "jsonrpc": "2.0",
  "method": "workflows.execute",
  "params": { "input": { "key1": "value1", "key2": "value2" }, "workflow": { "workflowID": "a1b2c3..." } }
}
```

Then compute: `digest = "0x" + sha256(sorted_json_string)`

> **CAUTION: Key ordering is critical**
>
> The digest **must** be computed from a JSON string with keys sorted in ascending lexicographic order at all nesting
> levels. Incorrect ordering will cause signature verification to fail.

### 3. Signature

The signature is an ECDSA signature of the message `<base64url(header)>.<base64url(payload)>` using your private key.

**Signing process:**

1. Concatenate the encoded header and payload: `message = base64url(header) + "." + base64url(payload)`
2. Sign the message using ECDSA with your private key:
   - Prepend the Ethereum signed message prefix: `"\x19Ethereum Signed Message:\n" + len(message) + message`
   - Hash the prefixed message with Keccak256
   - Sign the hash using your private key
3. Extract the signature components: `r` (32 bytes), `s` (32 bytes), `v` (1 byte, recovery ID)
4. Concatenate: `signature_bytes = r || s || v`
5. Base64url-encode the signature bytes

## Reference implementations

Manual JWT generation requires careful cryptographic operations. Use these reference implementations as guidance:

### For Go

Production-grade utilities:

- **JWT creation**: <a href="https://github.com/smartcontractkit/chainlink/blob/develop/core/utils/jwt.go" target="_blank" rel="noopener noreferrer">jwt.go</a> - See the `CreateRequestJWT` method for complete JWT generation
- **ECDSA signatures**: <a href="https://github.com/smartcontractkit/chainlink/blob/develop/core/utils/eth_signatures.go" target="_blank" rel="noopener noreferrer">eth\_signatures.go</a> - See the `GenerateEthSignature` method for Ethereum-compatible signing

### For TypeScript/JavaScript

The CRE SDK includes a reference implementation using `viem`:

- **Complete implementation**: <a href="https://github.com/smartcontractkit/cre-sdk-typescript/tree/main/packages/cre-http-trigger/src" target="_blank" rel="noopener noreferrer">cre-http-trigger source code</a>
- Key files:
  - `create-jwt.ts` - JWT header, payload, and signing logic
  - `utils.ts` - SHA256 hashing and base64url encoding helpers

### For testing

If you're testing deployed workflows during development, use the [Local Testing Tool](/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool) which runs a local proxy server that handles the entire JWT generation and request flow automatically.

## Example request (conceptual)

Here's what a complete curl request looks like:

```bash
curl -X POST https://01.gateway.zone-a.cre.chain.link \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGciOiJFVEgiLCJ0eXAiOiJKV1QifQ.eyJkaWdlc3QiOiIweDRhMWYyYjNjNGQ1ZTZmN2E4YjljMGQxZTJmM2E0YjVjNmQ3ZThmOWEwYjFjMmQzZTRmNWE2YjdjOGQ5ZTBmMWEiLCJpc3MiOiIweGIwOEUwMDRiZDJiNWFGZjFGNUY5NTBkMTQxZjQ0OUIxYzA1ODAwZWIiLCJpYXQiOjE3MzM4MzIwMDAsImV4cCI6MTczMzgzMjMwMCwianRpIjoiNTUwZTg0MDAtZTI5Yi00MWQ0LWE3MTYtNDQ2NjU1NDQwMDAwIn0.r7s8v9recoveryId..." \
  -d '{
    "jsonrpc": "2.0",
    "id": "req-123",
    "method": "workflows.execute",
    "params": {
      "input": {
        "userId": "user_123",
        "action": "purchase",
        "amount": 100
      },
      "workflow": {
        "workflowID": "a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890a1b2c3d4e5f67890"
      }
    }
  }'
```

## Response format

### Success response

When your request is successfully accepted, the gateway returns a JSON-RPC response:

```json
{
  "jsonrpc": "2.0",
  "id": "req-123",
  "method": "workflows.execute",
  "result": {
    "workflow_id": "<your-workflow-id>",
    "workflow_execution_id": "<your-workflow-execution-id>",
    "status": "ACCEPTED"
  }
}
```

**Response fields:**

| Field                          | Description                                                                                                 |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `jsonrpc`                      | JSON-RPC version (always `"2.0"`)                                                                           |
| `id`                           | The request ID you provided in the request                                                                  |
| `method`                       | The method called (always `"workflows.execute"`)                                                            |
| `result.workflow_id`           | Your workflow ID (with `0x` prefix)                                                                         |
| `result.workflow_execution_id` | Unique execution ID for this workflow run (use this to track execution in the CRE UI)                       |
| `result.status`                | Execution status (typically `"ACCEPTED"` when the workflow trigger is successfully accepted by the gateway) |

> **TIP: Track your execution**
>
> Copy the `workflow_execution_id` to track this specific execution in the [CRE
> UI](https://app.chain.link/cre/workflows). You can view logs, events, and execution details using this ID.

### Error response

If the request fails (e.g., invalid JWT, unauthorized key, workflow not found), the gateway returns an error response. Example:

```json
{
  "jsonrpc": "2.0",
  "id": "req-123",
  "method": "",
  "error": {
    "code": -32600,
    "message": "Auth failure: signer '0x...' is not authorized for workflow '0x...'. Ensure that the signer is registered in the workflow definition"
  }
}
```

> **NOTE: HTTP status codes**
>
> Error responses typically return HTTP status `400 Bad Request`. The JSON-RPC error object provides detailed
> information about what went wrong.

## Verifying execution

After triggering your workflow, verify execution in the CRE UI:

1. Go to <a href="https://app.chain.link/cre/workflows" target="_blank" rel="noopener noreferrer">app.chain.link/cre/workflows</a>
2. Click on your workflow
3. Check the **Execution** tab for recent runs
4. Click on an **Execution ID** to view detailed logs and events

See [Monitoring & Debugging Workflows](/cre/guides/operations/monitoring-workflows) for complete monitoring guidance.

## Security considerations

### Private key protection

- **Never commit private keys** to version control
- **Use environment variables** or secret management tools (e.g., AWS Secrets Manager, HashiCorp Vault)
- **Rotate keys periodically** and update your workflow's `authorizedKeys` if compromised

### Request expiration

- JWT tokens expire after the `exp` timestamp (max 5 minutes after `iat`)
- This prevents replay attacks with captured requests
- Generate new JWTs for each request

### Replay protection

- The `jti` (JWT ID) field provides replay protection
- Use a unique UUID for every request
- The gateway may reject duplicate `jti` values within the expiration window

## Next steps

### For easier testing

Manual JWT generation is complex and error-prone. For development and testing:

- **[Local Testing Tool](/cre/guides/workflow/using-triggers/http-trigger/local-testing-tool)** - Automatically generates JWTs and sends requests

### Additional resources

- **[HTTP Trigger SDK Reference](/cre/reference/sdk/triggers/http-trigger)** - Complete API documentation
- **[Monitoring Workflows](/cre/guides/operations/monitoring-workflows)** - Track execution history and debug issues