Create subscription

This endpoint subscribes to new transactions associated with the wallets.

NOTE: Consider all IDs as abstract strings, without making any assumptions about their format or relying on such assumptions. There is a non-zero probability that IDs may change in the future, and this should not result in any breaking changes.

Use Case

The main use case for the webhooks system is to send notifications, similar to push notifications in the Zerion App.

Setup Callback URL

If you want to use this endpoint to test how it works, you might use your dev key to start. It has limits: one subscription & maximum 5 wallets per subscription.
You may use callback URL from webhook.site to start from. If want use your custom - contact us at [email protected], and we will whitelist your URL.

If you want to use this endpoint in your production environment, you should contact us and provide the following details:

  • Your email associated with the API key
  • The URL that you prefer using as the callback (or host).

After we've whitelisted your callback URL (or host), you may start using this endpoint.

Note

  • Subscription Validity: Every subscription is valid for unlimited amount of time for production key, and one week for dev keys.
  • Transaction Prices: Prices are not attached to webhook notifications and will always be null. Prices are added to transactions in the backend after some time. To get prices, query the transactions endpoint by hash.
  • Delivery Guarantees: Webhook delivery is not guaranteed. If delivery fails three times, no further attempts will be made.
  • Order of Dispatch: The order of webhook dispatch is not guaranteed and may not correspond to the order of transactions occurring on the blockchain.

Callback Format and Signature Verification

Approved clients will receive notifications via POST requests to their provided URL. These notifications will include a signed notification object in the body (specified below in the Callback section) and a signature in the headers.

Clients should verify the signature provided in the headers of the webhook request to ensure the authenticity of the data. The following headers will be included:

  • X-Signature: The signature of the request.
  • X-Timestamp: The timestamp of the request.
  • X-Certificate-URL: The URL to download the public certificate used to verify the signature.

To verify the signature:

  1. Concatenate the X-Timestamp header value, the request body, and a newline character: $timestamp + "\n" + $request.body + "\n"
  2. Use the public certificate downloaded from the X-Certificate-URL header to verify the signature in the X-Signature header.

Example code in go for message verification:

package signature

import (
  "crypto"
  "crypto/rsa"
  "crypto/sha256"
  "crypto/x509"
  "encoding/base64"
  "encoding/pem"
  "errors"
  "github.com/stretchr/testify/assert"
  "testing"
)

// FetchCertificate fetches the certificate from the given URL
func FetchCertificate() (*x509.Certificate, error) {
  certBytes := certificate()
  block, _ := pem.Decode(certBytes)
  if block == nil || block.Type != "CERTIFICATE" {
    return nil, errors.New("failed to decode PEM block containing the certificate")
  }

  return x509.ParseCertificate(block.Bytes)
}

func certificate() []byte {
  return []byte(`-----BEGIN CERTIFICATE-----
MIIDMTCCAhmgAwIBAgIUDd3dFMswamyJ5A1bqF0nzS8v2wgwDQYJKoZIhvcNAQEL
BQAwQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC1plcmlvbiBJbmMuMRwwGgYJKoZI
hvcNAQkBFg1hcGlAemVyaW9uLmlvMB4XDTI0MDYyNzE1MzUzM1oXDTI1MDYyNzE1
MzUzM1owQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC1plcmlvbiBJbmMuMRwwGgYJ
KoZIhvcNAQkBFg1hcGlAemVyaW9uLmlvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAwcPVCPLDhS9dLA8s5J6GJ3t0+jWuUCFwI+q6c03xZnhCaz45FepN
MTiApbvPw1Zm8F8JQB4BRp/F5anokNcDSl/qmNtj3M/z/FrsVvGnSH2FOkZu9TLU
LTW5i8Q0LAYrpgiBHrTa2qrRXd2DiMrEs3QZVoylFYc9QIGet3SULPrlSsYEKxfB
iBZDoFw619NnV6/kBO8FS34Lc+WH5SNNHNnItRrxMv4DMAFyFajSn1IwV6LSWSNK
aPJHCzP/Omu95550HQKcXaJYNE/d99NrcLaFI2fCuEVd00nApFo5knKs0FiXpGca
l3cLOQG5SCOzUOjQb6X5CynEV+0QiyYxDwIDAQABoyEwHzAdBgNVHQ4EFgQUVL4m
u0PcI4nJGUS8syLi5DNL44YwDQYJKoZIhvcNAQELBQADggEBAKaA1oqW0D6KxvIp
IZxWf02XK/YFYwxKV55Vas0VWlzNemE2IjlIj0tknZt0EiM9um2FC27U9n3u0ApS
UDrk96dQ+/RY3T3fiuXysa3ZL05OpreRk0aPuFU9rB4iLTgFiv1G/X5XXJ8O7OQb
48u0vQnYXjT/nt72TMUoakjZ68QsP64FkG8mcK62Tg+FVWB9YWTFc0wOjsOt9RzJ
muKCQ7qx7L1GhkxKX4ZhrYItsH1DzXjeP5aniZgLBSPbxt01tUrSjOGN5CLOpdG8
iOnAFP+Nz8S0h2C7hppOHgC+uxY285UrzAZQoMbCREMV+0Mq/aqdF1B6qoKGNGqL
kFbUhvo=
-----END CERTIFICATE-----
`)
}

func VerifySignature(cert *x509.Certificate, message, signature string) error {
  pubKey := cert.PublicKey.(*rsa.PublicKey)

  hashed := sha256.Sum256([]byte(message))
  sigBytes, err := base64.StdEncoding.DecodeString(signature)
  if err != nil {
    return err
  }

  return rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, hashed[:], sigBytes)
}

func TestVerifySignature(t *testing.T) {
  // Example usage
  x509Cert, err := FetchCertificate()
  assert.NoError(t, err)

  xTimestamp := "2024-07-31T00:17:36Z"
  xSignature := "t65gdR8z3NGh/OQRPzGMFmw36JhDNvOe6LxL6K2hCd3SdYQoTGr76dAy1CpsX2G8XVOIYUIctUQvgICQvtDctVjkRZmXuQDvXHOmiJE0ZknORgjVLFoo5JRYKvwt3EPp6SMN7RtedIX17rH1s2Vp3GRQWSjzN7C/cNgInhCQOP0UDjYlaeNT/yW4B2Qt4uY01yK0YhvQJaFHN+NNr7DZAt4FJuDppItqjaYbHTaFNqLlpI1IX7YvQWVhEYTJY6M4T9IdcGYPJKDljckjvmj9mDHZeh/Y6w8eXjLziMSFvlhJeSn1kBIR3nS7lTcwFNv1CPxD3MM7VB++te3mBbFubg=="
  messageBody := `{"data":{"attributes":{"timestamp":"2024-07-31T00:17:36.661896043Z"},"id":"15daee90-5028-4b4c-bd49-b4d43fa1a89e","type":"callback"},"included":[{"attributes":{"application_metadata":{"contract_address":"0x8286d601a0ed6cf75e067e0614f73a5b9f024151","method":{"id":"0x7859bb8d","name":""}},"approvals":[],"fee":{"fungible_info":{"flags":{"verified":true},"icon":{"url":"https://cdn.zerion.io/eth.png"},"implementations":[{"address":"","chain_id":"redstone","decimals":18},{"address":"","chain_id":"polygon-zkevm","decimals":18},{"address":"","chain_id":"optimism","decimals":18},{"address":"","chain_id":"zksync-era","decimals":18},{"address":"","chain_id":"mode","decimals":18},{"address":"","chain_id":"base","decimals":18},{"address":"","chain_id":"ethereum","decimals":18},{"address":"","chain_id":"aurora","decimals":18},{"address":"","chain_id":"scroll","decimals":18},{"address":"","chain_id":"rari","decimals":18},{"address":"","chain_id":"astar-zkevm","decimals":18},{"address":"","chain_id":"arbitrum","decimals":18},{"address":"","chain_id":"zora","decimals":18},{"address":"","chain_id":"blast","decimals":18},{"address":"","chain_id":"linea","decimals":18},{"address":"","chain_id":"manta-pacific","decimals":18}],"name":"Ethereum","symbol":"ETH"},"price":null,"quantity":{"decimals":18,"float":0.0000016785001958,"int":"1678500195825","numeric":"0.000001678500195825"},"value":null},"flags":{"is_trash":false},"hash":"0xbbcfb0ac5e466ded168794a162da334634fee3f95adfdb55392999f91b4c6d41","mined_at":"2024-07-31T00:17:35Z","mined_at_block":7490818,"nonce":250,"operation_type":"execute","sent_from":"0xfc0f1b3fb88c5ab19e77a6f7d4d637272e71e684","sent_to":"0x8286d601a0ed6cf75e067e0614f73a5b9f024151","status":"confirmed","transfers":[]},"id":"a65b2541c58a5908a7333480f0ac6792","relationships":{"chain":{"id":"linea","type":"chains"},"dapp":{"id":"","type":"dapps"}},"type":"transactions"}]}`

  message := xTimestamp + "\n" + messageBody + "\n"

  err = VerifySignature(x509Cert, message, xSignature)
  assert.NoError(t, err)
}
Callback
Language
Credentials
Basic
base64
:
Click Try It! to start a request and see the response here!