Triggering Deployed Workflows

Once you've deployed a workflow 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

Prerequisites

  • Deployed workflow: Your workflow must be deployed with an HTTP trigger. See Deploying Workflows.
  • Workflow ID: Available from deployment output or the CRE UI.
  • Private key: The private key corresponding to one of the authorizedKeys configured in your HTTP trigger.

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:

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

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

From the CRE UI

  1. Log in to cre.chain.link/workflows
  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:

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

FieldDescription
jsonrpcAlways "2.0" (JSON-RPC version)
idUnique identifier for this request (any string, used for tracking)
methodAlways "workflows.execute"
params.inputYour custom JSON payload (passed to your workflow callback)
params.workflow.workflowIDYour 64-character workflow ID (no 0x prefix)

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:

{
  "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:

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

Payload fields:

FieldDescription
digestSHA256 hash of the JSON-RPC request body (with 0x prefix)
issIssuer - your EVM address (the public key corresponding to your private key)
iatIssued at time (Unix timestamp in seconds)
expExpiration time (Unix timestamp, max 5 minutes after iat)
jtiJWT 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:

{
  "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:

{
  "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)

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: jwt.go - See the CreateRequestJWT method for complete JWT generation
  • ECDSA signatures: eth_signatures.go - See the GenerateEthSignature method for Ethereum-compatible signing

For TypeScript/JavaScript

The CRE SDK includes a reference implementation using viem:

  • Complete implementation: cre-http-trigger source code
  • 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 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:

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:

{
  "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:

FieldDescription
jsonrpcJSON-RPC version (always "2.0")
idThe request ID you provided in the request
methodThe method called (always "workflows.execute")
result.workflow_idYour workflow ID (with 0x prefix)
result.workflow_execution_idUnique execution ID for this workflow run (use this to track execution in the CRE UI)
result.statusExecution status (typically "ACCEPTED" when the workflow trigger is successfully accepted by the gateway)

Error response

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

{
  "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"
  }
}

Verifying execution

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

  1. Go to cre.chain.link/workflows
  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 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:

Additional resources

Get the latest Chainlink content straight to your inbox.