Skip to main content

JSON-RPC API Documentation

The Hookah JSON-RPC API provides programmatic access to Radix blockchain operations, webhook management, trigger configuration, and transaction intent handling.

Base URL

  • Development/Local: http://localhost:3000/api/jsonrpc
  • Production: https://app.hookah.ing/api/jsonrpc

API Structure

All requests follow JSON-RPC 2.0 specification:

  • Use HTTP POST method
  • Include Content-Type: application/json header
  • Authentication required for protected endpoints via Authorization: Bearer <token> header

Authentication Requirements

🔓 Public Methods (No authentication required):

  • auth.generateChallenge
  • ret.virtualAccountAddressFromPublicKey
  • trigger.getValidEventNames

🔐 Protected Methods (Authentication required):

  • auth.getSession
  • auth.signInWithProof (generates token)
  • All webhook.* methods
  • All trigger.* methods (except getValidEventNames)
  • All transactionIntent.* methods
  • All log.* methods

Authentication Flow

1. Generate Challenge 🔓

Generate a cryptographic challenge for authentication.

{
"jsonrpc": "2.0",
"id": 1,
"method": "auth.generateChallenge"
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": "challenge_string_here"
}

2. Sign In with Proof 🔓

Authenticate using a signed challenge.

{
"jsonrpc": "2.0",
"id": 1,
"method": "auth.signInWithProof",
"params": {
"challenge": "challenge_string",
"proof": {
"signature": "hex_signature",
"curve": "curve25519",
"publicKey": "hex_public_key"
}
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"token": "jwt_token",
"session": {
"userId": "user_id"
}
}
}

3. Get Session 🔐

Retrieve current session information.

{
"jsonrpc": "2.0",
"id": 1,
"method": "auth.getSession"
}

Headers:

Authorization: Bearer <jwt_token>

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"session": {
"userId": "user_id"
}
}
}

Radix Engine Toolkit (RET) Methods

Get Virtual Account Address 🔓

Derive a virtual account address from a public key.

{
"jsonrpc": "2.0",
"id": 1,
"method": "ret.virtualAccountAddressFromPublicKey",
"params": {
"publicKey": "hex_public_key",
"curve": "curve25519",
"networkId": 1
}
}

Parameters:

  • publicKey: Hex-encoded public key
  • curve: Cryptographic curve (currently supports "curve25519")
  • networkId: Network identifier (1 for mainnet, 2 for stokenet)

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": "account_rdx129cd6fa9x5pmwx02j3zmqucpxlemqgh8lrjcgg932pppm349l0uud2"
}

Transaction Intent Management

Create Transaction Intent 🔐

Create a new transaction intent from a manifest.

{
"jsonrpc": "2.0",
"id": 1,
"method": "transactionIntent.createTransactionIntent",
"params": {
"manifest": {
"instructions": {
"kind": "String",
"value": "CALL_METHOD\n Address(\"component_address\")\n \"method_name\"\n Args();"
},
"blobs": []
},
"networkId": 2
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "transaction_id",
"intentHash": "hex_intent_hash"
}
}

Provide Signature 🔐

Add a signature to a transaction intent.

{
"jsonrpc": "2.0",
"id": 1,
"method": "transactionIntent.provideSignature",
"params": {
"transactionId": "transaction_id",
"signerPublicKey": "hex_public_key",
"curve": "EddsaEd25519",
"signature": "hex_signature"
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"status": "ReadyToSubmit"
}
}

Submit Transaction Intent 🔐

Submit a signed transaction intent to the network.

{
"jsonrpc": "2.0",
"id": 1,
"method": "transactionIntent.submitTransactionIntent",
"params": {
"transactionId": "transaction_id"
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"duplicate": false
}
}

Example: Complete Transaction Flow

  1. Get Virtual Account Address
  2. Authenticate (generate challenge, sign, get session)
  3. Create Transaction Intent with manifest
  4. Sign Intent Hash with private key
  5. Provide Signature to transaction
  6. Submit Transaction Intent

Webhook Management

Create Webhook 🔐

Create a new webhook endpoint.

{
"jsonrpc": "2.0",
"id": 1,
"method": "webhook.create",
"params": {
"name": "My Webhook",
"url": "https://example.com/webhook",
"headerKey": "X-Custom-Header",
"headerValue": "custom-value"
}
}

Parameters:

  • name: Optional webhook name
  • url: Webhook URL (must be valid URL)
  • headerKey: Optional custom header key
  • headerValue: Optional custom header value

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "webhook_id",
"name": "My Webhook",
"userId": "user_id",
"definition": {
"type": "webhook",
"url": "https://example.com/webhook",
"headerKey": "X-Custom-Header",
"headerValue": "custom-value"
},
"createdAt": "2025-01-01T00:00:00Z"
}
}

Note: The webhook URL and headers are stored in the definition object, not directly in the result.

Get Webhook by ID 🔐

Retrieve a specific webhook.

{
"jsonrpc": "2.0",
"id": 1,
"method": "webhook.getById",
"params": {
"id": "webhook_id"
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "webhook_id",
"name": "My Webhook",
"userId": "user_id",
"definition": {
"type": "webhook",
"url": "https://example.com/webhook",
"headerKey": "X-Custom-Header",
"headerValue": "custom-value"
},
"createdAt": "2025-01-01T00:00:00Z"
}
}

Get User's Webhooks 🔐

Retrieve all webhooks for the authenticated user.

{
"jsonrpc": "2.0",
"id": 1,
"method": "webhook.getByUserId"
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"id": "webhook_id_1",
"name": "My First Webhook",
"userId": "user_id",
"definition": {
"type": "webhook",
"url": "https://example.com/webhook1"
},
"createdAt": "2025-01-01T00:00:00Z"
},
{
"id": "webhook_id_2",
"name": "My Second Webhook",
"userId": "user_id",
"definition": {
"type": "webhook",
"url": "https://example.com/webhook2",
"headerKey": "Authorization",
"headerValue": "Bearer token"
},
"createdAt": "2025-01-02T00:00:00Z"
}
]
}

Update Webhook 🔐

Update an existing webhook.

{
"jsonrpc": "2.0",
"id": 1,
"method": "webhook.update",
"params": {
"id": "webhook_id",
"name": "Updated Webhook",
"url": "https://example.com/new-webhook",
"headerKey": "X-New-Header",
"headerValue": "new-value"
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "webhook_id",
"name": "Updated Webhook",
"userId": "user_id",
"definition": {
"type": "webhook",
"url": "https://example.com/new-webhook",
"headerKey": "X-New-Header",
"headerValue": "new-value"
},
"createdAt": "2025-01-01T00:00:00Z"
}
}

Remove Webhook 🔐

Delete a webhook.

{
"jsonrpc": "2.0",
"id": 1,
"method": "webhook.remove",
"params": {
"id": "webhook_id"
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"id": "webhook_id",
"name": "Deleted Webhook",
"userId": "user_id",
"definition": {
"type": "webhook",
"url": "https://example.com/webhook"
},
"createdAt": "2025-01-01T00:00:00Z"
}
]
}

Get Dashboard Data 🔐

Retrieve webhook statistics and counts.

{
"jsonrpc": "2.0",
"id": 1,
"method": "webhook.getDashboardData"
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"id": "webhook_id",
"name": "My Webhook",
"userId": "user_id",
"definition": {
"type": "webhook",
"url": "https://example.com/webhook"
},
"createdAt": "2025-01-01T00:00:00Z",
"successCount": 152,
"errorCount": 3,
"lastTriggered": "2025-01-15T14:30:00Z"
}
]
}

Trigger Management

Create Trigger 🔐

Create a new trigger to monitor blockchain events.

{
"jsonrpc": "2.0",
"id": 1,
"method": "trigger.create",
"params": {
"emitterAddress": "component_rdx1...",
"webhookId": "webhook_id",
"eventName": "DepositEvent",
"conditions": [
{
"id": "condition_1",
"field": "amount",
"comparator": "gt_n",
"value": "100"
}
]
}
}

Parameters:

  • emitterAddress: Radix component address to monitor
  • webhookId: ID of webhook to call when triggered
  • eventName: Name of the event to monitor
  • conditions: Optional array of trigger conditions

Trigger Conditions:

  • id: Unique identifier for the condition
  • field: Field name in the event data
  • comparator: Comparison operator:
    • Numeric: eq_n, neq_n, gt_n, lt_n, gte_n, lte_n
    • String: eq_s, neq_s, c_s (contains), nc_s (not contains), sw_s (starts with), ew_s (ends with)
    • Boolean: eq_b, neq_b
  • value: Value to compare against

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "trigger_id",
"webhookId": "webhook_id",
"userId": "user_id",
"status": "active",
"definition": {
"version": 2,
"rules": [...]
}
}
}

Get User's Triggers 🔐

Retrieve all triggers for the authenticated user.

{
"jsonrpc": "2.0",
"id": 1,
"method": "trigger.getByUserId"
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"id": "trigger_id_1",
"webhookId": "webhook_id",
"userId": "user_id",
"status": "active",
"emitterAddress": "component_rdx1...",
"eventName": "DepositEvent",
"definition": {
"version": 2,
"rules": [
{
"emitterAddress": "component_rdx1...",
"eventName": "DepositEvent",
"conditions": [
{
"id": "condition_1",
"field": "amount",
"comparator": "gt_n",
"value": "100"
}
]
}
]
},
"createdAt": "2025-01-01T00:00:00Z"
}
]
}

Get Triggers by Webhook ID 🔐

Retrieve triggers associated with a specific webhook.

{
"jsonrpc": "2.0",
"id": 1,
"method": "trigger.getByWebhookId",
"params": {
"webhookId": "webhook_id"
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"id": "trigger_id_1",
"webhookId": "webhook_id",
"userId": "user_id",
"status": "active",
"definition": {
"version": 2,
"rules": [
{
"emitterAddress": "component_rdx1...",
"eventName": "DepositEvent",
"conditions": []
}
]
},
"createdAt": "2025-01-01T00:00:00Z"
}
]
}

Get Valid Event Names 🔓

Retrieve available event names for a component address.

{
"jsonrpc": "2.0",
"id": 1,
"method": "trigger.getValidEventNames",
"params": {
"emitterAddress": "component_rdx1..."
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": [
"DepositEvent",
"WithdrawEvent",
"TransferEvent",
"SwapEvent",
"MintEvent",
"BurnEvent"
]
}

Update Trigger 🔐

Update an existing trigger.

{
"jsonrpc": "2.0",
"id": 1,
"method": "trigger.update",
"params": {
"id": "trigger_id",
"emitterAddress": "component_rdx1...",
"eventName": "DepositEvent",
"status": "active",
"webhookId": "webhook_id",
"conditions": [
{
"id": "condition_2",
"field": "status",
"comparator": "eq_s",
"value": "active"
}
]
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "trigger_id",
"webhookId": "webhook_id",
"userId": "user_id",
"status": "active",
"definition": {
"version": 2,
"rules": [
{
"emitterAddress": "component_rdx1...",
"eventName": "DepositEvent",
"conditions": [
{
"id": "condition_2",
"field": "status",
"comparator": "eq_s",
"value": "active"
}
]
}
]
},
"createdAt": "2025-01-01T00:00:00Z"
}
}

Remove Trigger 🔐

Delete a trigger.

{
"jsonrpc": "2.0",
"id": 1,
"method": "trigger.remove",
"params": {
"id": "trigger_id"
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"id": "trigger_id",
"webhookId": "webhook_id",
"userId": "user_id",
"status": "active",
"definition": {
"version": 2,
"rules": [
{
"emitterAddress": "component_rdx1...",
"eventName": "DepositEvent",
"conditions": []
}
]
},
"createdAt": "2025-01-01T00:00:00Z"
}
]
}

Log Management

Get Logs by Trigger ID 🔐

Retrieve execution logs for a specific trigger.

{
"jsonrpc": "2.0",
"id": 1,
"method": "log.getByTriggerId",
"params": {
"triggerId": "trigger_id"
}
}

Response:

{
"jsonrpc": "2.0",
"id": 1,
"result": [
{
"id": "log_id_1",
"triggerId": "trigger_id",
"status": "success",
"webhookUrl": "https://example.com/webhook",
"responseCode": 200,
"responseBody": "OK",
"eventData": {
"transactionId": "txid_rdx1...",
"amount": "150.50",
"from": "account_rdx1...",
"to": "account_rdx1..."
},
"createdAt": "2025-01-15T14:30:00Z"
},
{
"id": "log_id_2",
"triggerId": "trigger_id",
"status": "error",
"webhookUrl": "https://example.com/webhook",
"responseCode": 500,
"responseBody": "Internal Server Error",
"error": "Connection timeout",
"eventData": {
"transactionId": "txid_rdx1...",
"amount": "75.25"
},
"createdAt": "2025-01-15T13:15:00Z"
}
]
}

Error Handling

All methods follow JSON-RPC 2.0 error format:

{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000,
"message": "Error description"
}
}

Common Error Codes:

  • -32700: Parse error (invalid JSON)
  • -32600: Invalid request
  • -32601: Method not found
  • -32602: Invalid params/Internal error
  • NOT_FOUND: Resource not found
  • UNAUTHORIZED: Authentication required
  • INTERNAL_SERVER_ERROR: Server error

Network IDs

  • Mainnet: 1
  • Stokenet (Testnet): 2

Cryptographic Notes

  • Authentication: Uses Ed25519 signatures with curve25519
  • Transaction Signing: Uses EddsaEd25519 curve
  • Key Format: All keys and signatures are hex-encoded
  • Challenge Signing: Sign the raw challenge bytes
  • Intent Signing: Sign the intent hash (hex-decoded first)

Complete Workflow Example

Here's a practical example showing how to set up webhook monitoring for blockchain events:

1. Authenticate

// Generate challenge
const challengeResponse = await fetch(baseUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'auth.generateChallenge'
})
});

// Sign challenge and authenticate
const challenge = challengeResponse.result;
const signature = ed25519.sign(challenge, privateKey);

const authResponse = await fetch(baseUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'auth.signInWithProof',
params: {
challenge,
proof: {
signature: toHex(signature),
curve: 'curve25519',
publicKey: toHex(publicKey)
}
}
})
});

const token = authResponse.result.token;

2. Create Webhook

const webhookResponse = await fetch(baseUrl, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'webhook.create',
params: {
name: 'DEX Trade Monitor',
url: 'https://myapp.com/webhook/dex-trades',
headerKey: 'X-API-Key',
headerValue: 'your-api-key'
}
})
});

const webhookId = webhookResponse.result.id;

3. Create Trigger

const triggerResponse = await fetch(baseUrl, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'trigger.create',
params: {
emitterAddress: 'component_rdx1...dex_component',
webhookId: webhookId,
eventName: 'TradeEvent',
conditions: [
{
id: 'min_amount_filter',
field: 'amount',
comparator: 'gt_n',
value: '1000'
}
]
}
})
});

4. Monitor Events

Your webhook will now receive HTTP POST requests when trades > 1000 tokens occur on the specified DEX component.