Webhook Quickstart

What is Nodit Webhook?

Nodit Webhook은 추적하고자 하는 온체인 이벤트를 정의하여 사전에 등록해두면, Nodit 서버에서 해당 이벤트의 발생 여부를 추적하여 이벤트가 발생한 시점에 지정된 Webhook Endpoint를 호출하여 이벤트 정보를 전달하는 기능입니다. 프로젝트에서 구현한 Backend Endpoint를 통해 온체인 이벤트의 발생 여부와 내용을 비동기, 실시간으로 전달받을 수 있어 사용자 액션 추척, 토큰 액티비티 추적, 트랜잭션 처리여부 등을 효과적으로 모니터링할 수 있습니다. Nodit Webhook은 다음과 같은 순서를 통해 생성 및 사용할 수 있습니다.

  1. Webhook 수신을 위한 Endpoint 구현하기
  2. Nodit 콘솔 또는 API를 통해 원하는 Webhook 생성하기
    2-1. 모니터링 하고자 하는 대상 네트워크를 선택한 뒤 Event Type으로 추적하고자 하는 이벤트 정의
    2-2. 1에서 생성한 Webhook Endpoint 입력
  3. (Optional)Webhook 설정 정보를 수정 또는 삭제하기

🚀

Instant Webhook 옵션을 새롭게 지원합니다.

2025년 5월 30일부터 새롭게 지원되는 Instant Webhook 옵션은 모니터링 대상 이벤트가 포함된 블록의 확정 여부와 상관 없이, Nodit 노드에서 해당 이벤트가 감지되는 즉시 Webhook 메시지를 수신할 수 있는 옵션입니다. 이벤트의 확정(Confirmation) 여부 보다는 이벤트 발생에 대한 즉각적인 반응과 신속한 알림이 필요한 프로젝트에 적합합니다. 사용자 액션 트래킹, UI 반응 개선, 선제적 리스크 탐지 등과 같이 빠른 피드백이 중요한 애플리케이션에서 효과적으로 활용할 수 있습니다.

Instant Webhook 옵션을 비활성화하면 기존 Webhook과 동일하게 이벤트 트랜잭션이 포함된 블록이 확정된 이후에만 메시지가 발송됩니다. 블록이 롤백되거나 재구성되는 경우 이벤트가 최종적으로 발생하지 않았을 수도 있으므로, 데이터 확정성이 중요한 경우에는 옵션 비활성화를 통해 기존 방식의 Webhook을 사용하는 것을 권장합니다.

💡 API를 사용하여 Webhook을 생성 또는 조회하는 경우 isInstant 필드를 true 또는 false로 설정하여 옵션을 활성화/비활성화 할 수 있습니다.

Webhook 상태가 자동으로 비활성화 되었습니다. 어떻게 해야 하나요?

2025년 5월 20일부로 Nodit의 플랜 정책이 일부 변경되어, 이제 Starter 플랜 사용자의 경우 생성한 Webhook이 최대 9일간만 활성화 상태로 유지됩니다. Starter 플랜 계정의 Webhook은 생성 또는 재활성화 후 9일이 지나면 UTC 00:00:00에 자동으로 비활성화 되며, 비활성화 2일 전에 안내 메일이 Nodit 계정 이메일로 발송됩니다. 비활성화된 Webhook은 콘솔의 Webhook 메뉴나 API를 통해 직접 재활성화할 수 있으며, 재활성화 시 다시 최대 9일간 사용 가능합니다.

Webhook을 지속적으로 사용하려면, 정기적으로 상태를 확인하여 필요시 직접 재활성화하시거나, 더 긴 사용을 원하실 경우 플랜 업그레이드를 권장드립니다.


Webhook API 사용 예제

1. 환경 세팅

1-1. Nodit 콘솔 가입

Nodit에서는 다양한 블록체인 네트워크에 연결할 수 있는 Node 서비스를 제공합니다. 아래 링크를 클릭하여 Nodit Console에 접속하여 회원가입을 진행하세요.

1-2. Webhook Listener Endpiont 얻기

webhook 생성을 위해서는 알림을 받을 별도의 Webhook Listener 서버가 필요합니다. 이 서버는 외부의 이벤트 통지를 받아 처리하는 역할을 합니다. 서비스 운영을 위해서는 Webhook Listener 서버를 직접 구축해야 하지만, 이번 예제에서는 webhook 응답만 확인하기 때문에 써드파티 서비스를 활용합니다.

[써드파티 서비스 사용 예시]

  • Postman Mockserver: Postman Mockserver를 사용하면 API를 모의할 수 있으며, Webhook 요청을 받을 수 있는 임시 URL을 제공받습니다. 설정은 간단하며, Postman의 Mock 서버 생성 기능을 통해 쉽게 구성할 수 있습니다. 자세한 설정 방법은 아래 링크에서 확인할 수 있습니다.
    ▶︎ Set up Postman Mock server

  • Webhook.site: Webhook.site는 실시간으로 Webhook 데이터를 캡처하고 확인할 수 있는 서비스를 제공합니다. 이 서비스를 사용하면 별도의 서버 구축 없이 즉시 Webhook 테스트를 시작할 수 있습니다. 아래 링크를 클릭하면 무료 사용할 수 있는 Webhook Listener Endpoint를 얻을 수 있습니다.
    ▶︎ Webhook.site

이번 예제에서는 Webhook.site를 활용하여 Webhook 응답을 확인합니다. Webhook.site에 접속하여 제공되는 unique URL을 복사합니다.

webhook.site 화면

webhook.site 화면

2. Webhook 생성하기

콘솔 혹은 Webhook API를 사용하여 원하는 이벤트를 구독할 수 있습니다. 이 예제에서는 Webhook API를 활용하여 BLOCK_PERIOD 이벤트를 구독하는 Webhook을 생성합니다.

  • X-API-KEY: Nodit 콘솔에서 제공된 실제 API 키를 입력합니. API 키는 서비스에 안전하게 접근하고, 사용자의 인증을 확인하는 데 필수적인 요소입니다.
  • webhookUrl: 구독하고자 하는 이벤트의 알림을 받을 Webhook Listener Endpoint를 입력합니다. 위에서 복사한 Webhook Listener Endpoint를 webhookUrl에 붙여넣습니다.
curl --request POST \
     --url https://web3.nodit.io/v1/ethereum/mainnet/webhooks \
     --header 'X-API-KEY: {Your API key}' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '
{
  "eventType": "BLOCK_PERIOD",
  "description": "Webhook Test",
  "notification": {
    "webhookUrl": "{Your webhook listener endpoint}"
  },
  "condition": {
    "period": 1
  }
}
'

위의 스크립트를 실행하고 webhook이 성공적으로 생성되면, 성공 메세지와 함께 subscription ID을 포함한 응답을 반환합니다. 아래는 생성 예시입니다.

{
  "subscriptionId": "2361",
  "description": "Webhook test",
  "protocol": "ETHEREUM",
  "network": "MAINNET",
  "eventType": "BLOCK_PERIOD",
  "notification": {
    "webhookUrl": "https://example.com/webhook"
  },
  "signingKey": "cd5...d12",
  "condition": {
    "period": 1
  },
  "createdAt": "2024-04-29T08:04:11.098Z"
}

3. Webhook Listener 서버에서 응답 확인하기

Webhook이 정상적으로 생성되면, 구독하는 이벤트가 발생할 때마다 Webhook Listener 서버에 알림을 전송합니다. 아래는 Webhook.site에서 알림을 받은 예시입니다.

{
  "subscriptionId": "2347",
  "description": "Webhook test",
  "protocol": "ETHEREUM",
  "network": "MAINNET",
  "subscriptionType": "WEBHOOK",
  "notification": {
    "webhookUrl": "https://webhook.site/c3aa6f3b-e19d-416c-ab24-2659ffc0f304"
  },
  "signingKey": "0dc...286",
  "eventType": "BLOCK_PERIOD",
  "event": {
    "period": 5,
    "message": {
      "parent_hash": "0x4cff8863b4dadd17424574f71898d46dc4170567e68fece6514c3c0fd3c6aa37",
      "sha3_uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
      "miner": "0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5",
      "state_root": "0x0ac76dcf2b9b460db6aa1b87aba041a16fdc626d454c6c8722753a54a4180684",
      "transactions_root": "0x6504d7b34c36760e9de9c8ab5468c71f9442aab965a29234822651557b076a83",
      "receipts_root": "0x9b7bebea2e5bdc0055e1b937e6993cc6b52a533ce68373b6e91b61bd4d2b570d",
      "logs_bloom": "0xbffffdfdfff7ffff7fdfffefdffffffffdbbffffcfffffffaffffff7feffffffffffffedf7cfffdf7fefff7ffffbfddfbfffef6ffbfdfffdfffbfc3df3bffffbffefbffbff6fffefffaf67fffef7fffefffff7f7ffffffff9fffffefeffffffffbffefff7afff5f7f7fffffffbbdfbff9fbffefb9ffdffeffffdfffbffffdafffefefbdffdffff7ef8fdfffbffffffffffbfdfbf7ff6f7fffffbebefffdfffffbeffdfff9fdfef7fafffffffffffffefbeffffffffffffffffdffffdbfe7fbfff7fdffffbfffcfdb7fffffffbffffbffffbffffefffddffff7fefffadffffffbfffffffffffffdeffbedfdf7bf1fbdffafffffefffdffffff7fdfffeffbffffd",
      "difficulty": "0",
      "gas_limit": 30000000,
      "gas_used": 29997074,
      "extra_data": "0x6265617665726275696c642e6f7267",
      "mix_hash": "0xd7af35f660850b15564a7667678d51a9db1bbe045702efbb2b8034d98b01c2f4",
      "nonce": "0x0000000000000000",
      "hash": "0xd69b6a597874ad7382569e85b93bed4e8d0d6c7152b9ac59677611fa00a568a6",
      "size": 155824,
      "total_difficulty": "58750003716598352816469",
      "transactions": [
        "0xef99067235b9d30831f5161cdfb9cd1a1b24f04fc9a694b120ef8e568bd70234",
				// ... snip
        "0x586442f7566519e7e3f026bfd318a65f559783cafe0f5a9b3162dc7f50c0d6cb"
      ],
      "transaction_count": 318,
      "log_count": 1548,
      "base_fee_per_gas": 5838584039,
      "withdrawals_root": "0xc0419b57a2665a2682834b323193cdbc56f13698aed0467a028b586ae9720488",
      "withdrawal_count": 16,
      "blob_gas_used": "0x0",
      "excess_blob_gas": "0x60000",
      "parent_beacon_block_root": "0x40735f721e4de4c63825f5885795ade7ac314a8502953ef14c074b64b70b2b4e",
      "type": "block",
      "number": 19758850,
      "timestamp": 1714368119
    }
  },
  "createdAt": "2024-04-29T05:23:46.838Z"
}

🚧

Kaia Webhook 데이터에 대하여

Kaia 체인에서 Webhook을 사용하는 경우 Webhook의 payload 구조 및 일부 필드의 형식이 다른 이더리움 계열 체인의 데이터와 상이할 수 있습니다. 이는 체인별로 정의된 고유한 데이터 명세를 유지하기 위한 것으로, Kaia Webhook 데이터는 노드의 kaia namespace에 속한 API 응답 데이터를 기준으로 생성됩니다. 예를 들어, 트랜잭션 관련 Webhook payload의 transaction_type 필드는 Kaia와 이더리움에서 아래와 같이 상이한 형식의 값으로 반환됩니다.

  • 이더리움의 transaction_type: 2 (Number 타입)
  • Kaia의 transaction_type: "TxTypeEthereumDynamicFee" (String 타입)

4. Webhook 수정 및 조회하기

이제 등록한 Webhook을 수정해본 뒤, 영구적으로 삭제하는 방법을 알아보겠습니다.

Nodit Webhook 서비스에는 알림을 일시 정지할 수 있는 기능을 제공하고 있습니다. 일시정지를 한 경우, 등록한 Webhook은 삭제되지 않고 알림만 해제된 상태가 됩니다. 아래의 예제 스크립트를 실행하여 isActive 필드를 false로 설정해보세요. (이때, 유효한 SUBSCRIPTION_ID와 YOUR_API_KEY를 입력해야 합니다.)

curl --request PATCH \
     --url https://web3.nodit.io/v1/ethereum/mainnet/webhooks/{SUBSCRIPTION_ID} \
     --header 'X-API-KEY: {YOUR_API_KEY}' \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --data '{
     "isActive":false
}'

result가 true라는 응답을 반환하면 수정이 성공적으로 진행되었음을 의미합니다.

{
  "result": true
}

이번엔 수정된 내용을 확인하기 위해 Webhook 정보를 조회합니다. (이때, 유효한 SUBSCRIPTION_ID와 YOUR_API_KEY를 입력해야 합니다.)

curl --request GET \
     --url 'https://web3.nodit.io/v1/ethereum/mainnet/webhooks?subscriptionId={SUBSCRIPTION_ID}' \
     --header 'X-API-KEY: {YOUR_API_KEY}' \
     --header 'accept: application/json'

{
  "total": 1,
  "rpp": 10,
  "page": 1,
  "items": [
    {
      "subscriptionId": "2361",
      "description": "webhook Test",
      "environmentId": "9999999999999999999",
      "protocol": "ETHEREUM",
      "network": "MAINNET",
      "subscriptionType": "WEBHOOK",
      "eventType": "BLOCK_PERIOD",
      "notification": {
        "webhookUrl": "https://example.com/webhook"
      },
      "signingKey": "0a2...2fd",
      "isActive": false,
      "updatedAt": "2024-04-29T08:20:20.000Z",
      "createdAt": "2024-04-29T08:17:21.826Z",
      "condition": {
        "period": 1
      }
    }
  ]
}

5. Webhook 삭제하기

마지막으로 구독 중인 Webhook을 삭제해보겠습니다. 단, 한 번 삭제를 진행하면 되돌릴 수 없기 때문에 신중하게 삭제 작업을 결정해야 합니다. 삭제 과정은 해당 Webhook에 대한 모든 설정과 데이터 전송을 중지시키므로, 이 이상 이벤트 알람을 받지 못하게 됩니다. 아래 예제 스크립트를 이용하여 이번 예제에서 생성한 Webhook을 삭제해보세요.

curl --request DELETE \
     --url https://web3.nodit.io/v1/ethereum/mainnet/webhooks/{SUBSCRIPTION_ID} \
     --header 'X-API-KEY: {YOUR_API_KEY}' \
     --header 'accept: application/json'

result가 true라는 응답을 반환하면 삭제가 성공적으로 진행되었음을 의미합니다.

{
  "result": true
}

Webhook Retry 정책

Nodit Webhook은 현재 최대 1번의 Retry를 지원합니다. webhookUrl 호출 후 200 OK 응답을 받지 못한 경우, 최초 요청 시점으로부터 15초 후 Webhook 데이터 전달을 위한 재호출이 실행됩니다.