Skip to main content
POST
/
v1
/
account
/
{accountSlug}
/
project
/
{projectSlug}
/
actions
/
publishFile
cURL
# Block Web3 Action
curl 'https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/actions/publishFile' \
  -H 'X-Access-Key: ${TENDERLY_ACCESS_KEY}' \
  -H 'content-type: application/json' \
  --data-raw $'{"action":{"name":"block-action","description":"Triggers on every 10th block on ETH Mainnet and Polygon.","source":"// Do not change function name.\\nconst actionFn = async (context, blockEvent) => {\\n    console.log(blockEvent)\\n\\n    // To access project\'s secret\\n    // let secret = await context.secrets.get(\'MY-SECRET\')\\n\\n    // To access project\'s storage\\n    // let value = await context.storage.getStr(\'MY-KEY\')\\n    // await context.storage.putStr(\'MY-KEY\', \'MY-VALUE\')\\n\\n    // Your logic goes here :)\\n}\\n// Do not change this.\\nmodule.exports = { actionFn }","triggerType":"BLOCK","runtime":"V2","function":"actionFn","invocationType":"ASYNC","trigger":{"type":"block","block":{"network":["1","137"],"blocks":10}}},"deploy":true}' \
  --compressed

# Periodic Web3 Action
curl 'https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/actions/publishFile' \
  -H 'X-Access-Key: ${TENDERLY_ACCESS_KEY}' \
  -H 'content-type: application/json' \
  --data-raw $'{"action":{"name":"periodic-1hour","description":"CRON job triggered every 1 hour","source":"// Do not change function name.\\nconst actionFn = async (context, periodicEvent) => {\\n    console.log(periodicEvent)\\n\\n    // To access project\'s secret\\n    // let secret = await context.secrets.get(\'MY-SECRET\')\\n\\n    // To access project\'s storage\\n    // let value = await context.storage.getStr(\'MY-KEY\')\\n    // await context.storage.putStr(\'MY-KEY\', \'MY-VALUE\')\\n\\n    // Your logic goes here :)\\n}\\n// Do not change this.\\nmodule.exports = { actionFn }","triggerType":"PERIODIC","runtime":"V2","function":"actionFn","invocationType":"ASYNC","trigger":{"type":"periodic","periodic":{"cron":"0 * * * *","interval":"1h"}}},"deploy":true}' \
  --compressed

# Webhook Web3 Action
curl 'https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/actions/publishFile' \
  -H 'X-Access-Key: ${TENDERLY_ACCESS_KEY}' \
  -H 'content-type: application/json' \
  --data-raw $'{"action":{"name":"webhook-action","description":"Non-authenticated webhook action. You will be able to make a request without using a valid Tenderly token.","source":"// Do not change function name.\\nconst actionFn = async (context, webhookEvent) => {\\n    console.log(webhookEvent)\\n\\n    // To access project\'s secret\\n    // let secret = await context.secrets.get(\'MY-SECRET\')\\n\\n    // To access project\'s storage\\n    // let value = await context.storage.getStr(\'MY-KEY\')\\n    // await context.storage.putStr(\'MY-KEY\', \'MY-VALUE\')\\n\\n    // Your logic goes here :)\\n}\\n// Do not change this.\\nmodule.exports = { actionFn }","triggerType":"WEBHOOK","runtime":"V2","function":"actionFn","invocationType":"ASYNC","trigger":{"type":"webhook","webhook":{"authenticated":false}}},"deploy":true}' \
  --compressed
import requests

url = "https://api.tenderly.co/api/v1/account/{accountSlug}/project/{projectSlug}/actions/publishFile"

payload = {
    "action": {
        "name": "block-action",
        "description": "Triggers on every 10th block on ETH Mainnet and Polygon.",
        "source": "// Do not change function name.
const actionFn = async (context, blockEvent) => {
    console.log(blockEvent)

    // To access project's secret
    // let secret = await context.secrets.get('MY-SECRET')

    // To access project's storage
    // let value = await context.storage.getStr('MY-KEY')
    // await context.storage.putStr('MY-KEY', 'MY-VALUE')

    // Your logic goes here :)
}
// Do not change this.
module.exports = { actionFn }",
        "triggerType": "BLOCK",
        "runtime": "V2",
        "function": "actionFn",
        "invocationType": "ASYNC",
        "trigger": {
            "type": "block",
            "block": {
                "network": ["1", "137"],
                "blocks": 10
            }
        }
    },
    "deploy": True
}
headers = {
    "X-Access-Key": "<api-key>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.text)
const options = {
  method: 'POST',
  headers: {'X-Access-Key': '<api-key>', 'Content-Type': 'application/json'},
  body: JSON.stringify({
    action: {
      name: 'block-action',
      description: 'Triggers on every 10th block on ETH Mainnet and Polygon.',
      source: '// Do not change function name.\nconst actionFn = async (context, blockEvent) => {\n    console.log(blockEvent)\n\n    // To access project\'s secret\n    // let secret = await context.secrets.get(\'MY-SECRET\')\n\n    // To access project\'s storage\n    // let value = await context.storage.getStr(\'MY-KEY\')\n    // await context.storage.putStr(\'MY-KEY\', \'MY-VALUE\')\n\n    // Your logic goes here :)\n}\n// Do not change this.\nmodule.exports = { actionFn }',
      triggerType: 'BLOCK',
      runtime: 'V2',
      function: 'actionFn',
      invocationType: 'ASYNC',
      trigger: {type: 'block', block: {network: ['1', '137'], blocks: 10}}
    },
    deploy: true
  })
};

fetch('https://api.tenderly.co/api/v1/account/{accountSlug}/project/{projectSlug}/actions/publishFile', options)
  .then(res => res.json())
  .then(res => console.log(res))
  .catch(err => console.error(err));
<?php

$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://api.tenderly.co/api/v1/account/{accountSlug}/project/{projectSlug}/actions/publishFile",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => json_encode([
    'action' => [
        'name' => 'block-action',
        'description' => 'Triggers on every 10th block on ETH Mainnet and Polygon.',
        'source' => '// Do not change function name.
const actionFn = async (context, blockEvent) => {
    console.log(blockEvent)

    // To access project\'s secret
    // let secret = await context.secrets.get(\'MY-SECRET\')

    // To access project\'s storage
    // let value = await context.storage.getStr(\'MY-KEY\')
    // await context.storage.putStr(\'MY-KEY\', \'MY-VALUE\')

    // Your logic goes here :)
}
// Do not change this.
module.exports = { actionFn }',
        'triggerType' => 'BLOCK',
        'runtime' => 'V2',
        'function' => 'actionFn',
        'invocationType' => 'ASYNC',
        'trigger' => [
                'type' => 'block',
                'block' => [
                                'network' => [
                                                                '1',
                                                                '137'
                                ],
                                'blocks' => 10
                ]
        ]
    ],
    'deploy' => true
  ]),
  CURLOPT_HTTPHEADER => [
    "Content-Type: application/json",
    "X-Access-Key: <api-key>"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.tenderly.co/api/v1/account/{accountSlug}/project/{projectSlug}/actions/publishFile"

	payload := strings.NewReader("{\n  \"action\": {\n    \"name\": \"block-action\",\n    \"description\": \"Triggers on every 10th block on ETH Mainnet and Polygon.\",\n    \"source\": \"// Do not change function name.\\nconst actionFn = async (context, blockEvent) => {\\n    console.log(blockEvent)\\n\\n    // To access project's secret\\n    // let secret = await context.secrets.get('MY-SECRET')\\n\\n    // To access project's storage\\n    // let value = await context.storage.getStr('MY-KEY')\\n    // await context.storage.putStr('MY-KEY', 'MY-VALUE')\\n\\n    // Your logic goes here :)\\n}\\n// Do not change this.\\nmodule.exports = { actionFn }\",\n    \"triggerType\": \"BLOCK\",\n    \"runtime\": \"V2\",\n    \"function\": \"actionFn\",\n    \"invocationType\": \"ASYNC\",\n    \"trigger\": {\n      \"type\": \"block\",\n      \"block\": {\n        \"network\": [\n          \"1\",\n          \"137\"\n        ],\n        \"blocks\": 10\n      }\n    }\n  },\n  \"deploy\": true\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-Access-Key", "<api-key>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(string(body))

}
HttpResponse<String> response = Unirest.post("https://api.tenderly.co/api/v1/account/{accountSlug}/project/{projectSlug}/actions/publishFile")
  .header("X-Access-Key", "<api-key>")
  .header("Content-Type", "application/json")
  .body("{\n  \"action\": {\n    \"name\": \"block-action\",\n    \"description\": \"Triggers on every 10th block on ETH Mainnet and Polygon.\",\n    \"source\": \"// Do not change function name.\\nconst actionFn = async (context, blockEvent) => {\\n    console.log(blockEvent)\\n\\n    // To access project's secret\\n    // let secret = await context.secrets.get('MY-SECRET')\\n\\n    // To access project's storage\\n    // let value = await context.storage.getStr('MY-KEY')\\n    // await context.storage.putStr('MY-KEY', 'MY-VALUE')\\n\\n    // Your logic goes here :)\\n}\\n// Do not change this.\\nmodule.exports = { actionFn }\",\n    \"triggerType\": \"BLOCK\",\n    \"runtime\": \"V2\",\n    \"function\": \"actionFn\",\n    \"invocationType\": \"ASYNC\",\n    \"trigger\": {\n      \"type\": \"block\",\n      \"block\": {\n        \"network\": [\n          \"1\",\n          \"137\"\n        ],\n        \"blocks\": 10\n      }\n    }\n  },\n  \"deploy\": true\n}")
  .asString();
require 'uri'
require 'net/http'

url = URI("https://api.tenderly.co/api/v1/account/{accountSlug}/project/{projectSlug}/actions/publishFile")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-Access-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"action\": {\n    \"name\": \"block-action\",\n    \"description\": \"Triggers on every 10th block on ETH Mainnet and Polygon.\",\n    \"source\": \"// Do not change function name.\\nconst actionFn = async (context, blockEvent) => {\\n    console.log(blockEvent)\\n\\n    // To access project's secret\\n    // let secret = await context.secrets.get('MY-SECRET')\\n\\n    // To access project's storage\\n    // let value = await context.storage.getStr('MY-KEY')\\n    // await context.storage.putStr('MY-KEY', 'MY-VALUE')\\n\\n    // Your logic goes here :)\\n}\\n// Do not change this.\\nmodule.exports = { actionFn }\",\n    \"triggerType\": \"BLOCK\",\n    \"runtime\": \"V2\",\n    \"function\": \"actionFn\",\n    \"invocationType\": \"ASYNC\",\n    \"trigger\": {\n      \"type\": \"block\",\n      \"block\": {\n        \"network\": [\n          \"1\",\n          \"137\"\n        ],\n        \"blocks\": 10\n      }\n    }\n  },\n  \"deploy\": true\n}"

response = http.request(request)
puts response.read_body
{
  "actions": {
    "block-action": {
      "id": "349cbb00-64ad-47ec-bbcb-40bffa28559f",
      "index": 1,
      "actionId": "53712e55-eb77-4ce3-9140-685fd230396a",
      "parentActionId": "",
      "runtime": "V2",
      "function": "implementation:actionFn",
      "triggerType": "BLOCK",
      "trigger": {
        "type": "block",
        "block": {
          "network": [
            "1",
            "137"
          ],
          "blocks": 10
        }
      },
      "commitish": null,
      "source": "// Do not change function name.\nconst actionFn = async (context, blockEvent) => {\n    console.log(blockEvent)\n\n    // To access project's secret\n    // let secret = await context.secrets.get('MY-SECRET')\n\n    // To access project's storage\n    // let value = await context.storage.getStr('MY-KEY')\n    // await context.storage.putStr('MY-KEY', 'MY-VALUE')\n\n    // Your logic goes here :)\n}\n// Do not change this.\nmodule.exports = { actionFn }",
      "createdAt": "2023-12-14T18:47:19.26565Z",
      "deployRequested": true,
      "deployError": null,
      "invocationType": "ASYNC"
    }
  }
}
{
  "error": {
    "id": "596b1dc7-af60-477b-aab3-6c93eb92ddfa",
    "slug": "bad_request",
    "message": "Bad request input parameters"
  }
}
{
  "error": {
    "id": "596b1dc7-af60-477b-aab3-6c93eb92ddfa",
    "slug": "unauthorized",
    "message": "Unauthorized"
  }
}
{
  "error": {
    "id": "596b1dc7-af60-477b-aab3-6c93eb92ddfa",
    "slug": "insufficient_permissions",
    "message": "Insufficient permissions"
  }
}
{
  "error": {
    "id": "596b1dc7-af60-477b-aab3-6c93eb92ddfa",
    "slug": "resource_not_found",
    "message": "The resource you requested could not be found."
  }
}
{
  "error": {
    "id": "596b1dc7-af60-477b-aab3-6c93eb92ddfa",
    "slug": "internal_server_error",
    "message": "Internal server error"
  }
}

Authorizations

X-Access-Key
string
header
required

An API key is a token that a client provides when making API calls. Send it as the X-Access-Key request header on any endpoint:

curl '<API_ENDPOINT>' \
  -H 'X-Access-Key: ${TENDERLY_ACCESS_KEY}' \
  ...

Learn how to generate API access tokens at Tenderly Docs.

Path Parameters

accountSlug
string
required

Account slug of the user

projectSlug
string
required

Project slug of the account

Body

application/json

Create web3 action payload

action
action · object
required

A Web3 Action creation payload.

Example:
{
  "name": "block-action",
  "description": "Triggers on every 10th block on ETH Mainnet and Polygon.",
  "source": "// Do not change function name.\nconst actionFn = async (context, blockEvent) => {\n    console.log(blockEvent)\n\n    // To access project's secret\n    // let secret = await context.secrets.get('MY-SECRET')\n\n    // To access project's storage\n    // let value = await context.storage.getStr('MY-KEY')\n    // await context.storage.putStr('MY-KEY', 'MY-VALUE')\n\n    // Your logic goes here :)\n}\n// Do not change this.\nmodule.exports = { actionFn }",
  "triggerType": "BLOCK",
  "runtime": "V2",
  "function": "actionFn",
  "invocationType": "ASYNC",
  "trigger": {
    "type": "block",
    "block": { "network": ["1", "137"], "blocks": 10 }
  }
}
deploy
boolean
required

Should Web3 Action be immediately deployed.

Example:

true

Response

A successful response.

An object with details about created Web3 Action of Block type.