Keyboard shortcuts

Press โ† or โ†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

SDK Documentation Spark
Request API Key

Managing webhooks

Webhooks allow you to receive real-time notifications when events occur in your wallet, such as completed Lightning payments or on-chain deposits. The Spark service provider sends an HTTP POST request to your specified URL whenever a subscribed event occurs. Each webhook payload is signed using HMAC-SHA256 with the secret you provide during registration, allowing you to verify the authenticity of incoming notifications.

Event types

The following event types are available for webhook subscriptions:

Event typePayload typeDescription
WebhookEventType::LightningReceiveFinishedWebhookEventType.LIGHTNING_RECEIVE_FINISHEDWebhookEventType.lightningReceiveFinishedWebhookEventType.LightningReceiveFinishedWebhookEventType.LightningReceiveFinishedWebhookEventType.LightningReceiveFinishedWebhookEventType.LightningReceiveFinishedWebhookEventTypeLightningReceiveFinishedWebhookEventType.LightningReceiveFinishedSPARK_LIGHTNING_RECEIVE_FINISHEDA Lightning receive finished
WebhookEventType::LightningSendFinishedWebhookEventType.LIGHTNING_SEND_FINISHEDWebhookEventType.lightningSendFinishedWebhookEventType.LightningSendFinishedWebhookEventType.LightningSendFinishedWebhookEventType.LightningSendFinishedWebhookEventType.LightningSendFinishedWebhookEventTypeLightningSendFinishedWebhookEventType.LightningSendFinishedSPARK_LIGHTNING_SEND_FINISHEDA Lightning send finished
WebhookEventType::CoopExitFinishedWebhookEventType.COOP_EXIT_FINISHEDWebhookEventType.coopExitFinishedWebhookEventType.CoopExitFinishedWebhookEventType.CoopExitFinishedWebhookEventType.CoopExitFinishedWebhookEventType.CoopExitFinishedWebhookEventTypeCoopExitFinishedWebhookEventType.CoopExitFinishedSPARK_COOP_EXIT_FINISHEDA cooperative exit finished
WebhookEventType::StaticDepositFinishedWebhookEventType.STATIC_DEPOSIT_FINISHEDWebhookEventType.staticDepositFinishedWebhookEventType.StaticDepositFinishedWebhookEventType.StaticDepositFinishedWebhookEventType.StaticDepositFinishedWebhookEventType.StaticDepositFinishedWebhookEventTypeStaticDepositFinishedWebhookEventType.StaticDepositFinishedSPARK_STATIC_DEPOSIT_FINISHEDA static deposit claim finished

Webhook payload

When an event occurs, the Spark service provider sends an HTTP POST request to your webhook URL. The payload is a JSON object whose fields vary by event type. The request includes an X-Spark-Signature header containing the hex-encoded HMAC-SHA256 signature of the raw request body, computed using the secret you provided during registration.

All payloads share the following common fields:

FieldTypeDescription
idstringUnique identifier for the request
created_atstringISO 8601 timestamp of when the request was created
updated_atstringISO 8601 timestamp of the last update
networkstringThe network: MAINNET, REGTEST, SIGNET or TESTNET
request_statusstring | nullOutcome of the request: SUCCEEDED, FAILED or CANCELED. Its type also allows CREATED, IN_PROGRESS and UNKNOWN.
statusstringStatus of the request at the time of the event. Its values depend on the event type and are listed with each event below.
typestringThe event type, as listed under Event types
timestampstringISO 8601 timestamp of when this delivery attempt was sent

An amount is an object with an integer value and the unit of that value, such as SATOSHI or MILLISATOSHI. Each payload contains every field listed for its event type.

Lightning receive finished

The event is sent to the webhooks of the wallet that created the invoice. Lightning Address invoices are created by the LNURL server, so a wallet's own webhooks do not receive this event for its Lightning Address payments. See Lightning Address payment notifications for those payments.

FieldTypeDescription
statusstringA LightningReceiveRequestStatus value: INVOICE_CREATED, HTLC_RECEIVED, TRANSFER_CREATED, TRANSFER_CREATION_FAILED, PAYMENT_PREIMAGE_PENDING, PAYMENT_PREIMAGE_RECOVERED, PAYMENT_PREIMAGE_QUERYING_FAILED, PAYMENT_PREIMAGE_RECOVERING_FAILED, TRANSFER_CANCELED, HTLC_FAILED, LIGHTNING_PAYMENT_RECEIVED, TRANSFER_FAILED, TRANSFER_COMPLETED, REFUND_SIGNING_COMMITMENTS_QUERYING_FAILED, REFUND_SIGNING_FAILED
payment_preimagestring | nullHex-encoded payment preimage
receiver_identity_public_keystring | nullHex-encoded identity public key of the receiving wallet, when another wallet created the invoice
invoice_amountamountAmount of the invoice
htlc_amountamount | nullAmount of the received HTLC
{
  "type": "SPARK_LIGHTNING_RECEIVE_FINISHED",
  "id": "0194c7a2-5e1b-7c3d-9f00-3a1b2c4d5e6f",
  "created_at": "2026-01-15T14:32:00Z",
  "updated_at": "2026-01-15T14:32:00Z",
  "network": "MAINNET",
  "request_status": "SUCCEEDED",
  "status": "TRANSFER_COMPLETED",
  "payment_preimage": "0000000000000000000000000000000000000000000000000000000000000000",
  "receiver_identity_public_key": "000000000000000000000000000000000000000000000000000000000000000000",
  "invoice_amount": {
    "value": 100000,
    "unit": "SATOSHI"
  },
  "htlc_amount": {
    "value": 100000,
    "unit": "SATOSHI"
  },
  "timestamp": "2026-01-15T14:32:00Z"
}

Lightning send finished

FieldTypeDescription
statusstringA LightningSendRequestStatus value: CREATED, USER_TRANSFER_VALIDATION_FAILED, LIGHTNING_PAYMENT_INITIATED, LIGHTNING_PAYMENT_FAILED, LIGHTNING_PAYMENT_SUCCEEDED, PREIMAGE_PROVIDED, PREIMAGE_PROVIDING_FAILED, TRANSFER_COMPLETED, TRANSFER_FAILED, PENDING_USER_SWAP_RETURN, USER_SWAP_RETURNED, USER_SWAP_RETURN_FAILED, REQUEST_VALIDATED
encoded_invoicestringThe BOLT11 invoice
feeamountFee for paying the invoice
idempotency_keystring | nullIdempotency key of the send request
invoice_amountamountAmount of the invoice
payment_preimagestring | nullHex-encoded payment preimage
{
  "type": "SPARK_LIGHTNING_SEND_FINISHED",
  "id": "0194c7a2-5e1b-7c3d-9f00-3a1b2c4d5e6f",
  "created_at": "2026-01-15T14:32:00Z",
  "updated_at": "2026-01-15T14:32:00Z",
  "network": "MAINNET",
  "request_status": "SUCCEEDED",
  "status": "PREIMAGE_PROVIDED",
  "encoded_invoice": "lnbc500u1test...",
  "fee": {
    "value": 100,
    "unit": "SATOSHI"
  },
  "idempotency_key": "user-defined-key-123",
  "invoice_amount": {
    "value": 50000,
    "unit": "SATOSHI"
  },
  "payment_preimage": "0000000000000000000000000000000000000000000000000000000000000000",
  "timestamp": "2026-01-15T14:32:00Z"
}

Cooperative exit finished

FieldTypeDescription
statusstringA SparkCoopExitRequestStatus value: INITIATED, COMPLETE_REQUEST_RECEIVED, INBOUND_TRANSFER_CHECKED, TX_BROADCASTING_SCHEDULED, TX_BROADCASTING_FAILED, TX_BROADCASTED, ON_CHAIN_TX_CONFIRMED, INBOUND_TRANSFER_CLAIMING_FAILED, SUCCEEDED, EXPIRING_SCHEDULED, EXPIRING_FAILED, EXPIRED, FAILING_SCHEDULED, FAILING_FAILED, FAILED, TX_SIGNED, WAITING_ON_TX_CONFIRMATIONS, INBOUND_TRANSFER_CLAIMING_SCHEDULED
feeamountFee for the cooperative exit, excluding l1_broadcast_fee
withdrawal_addressstring | nullBitcoin address to withdraw to
l1_broadcast_feeamountOn-chain fee of the cooperative exit
exit_speedstring | nullRequested exit speed: FAST, MEDIUM or SLOW
coop_exit_txidstringId of the cooperative exit transaction
expires_atstringISO 8601 timestamp of when the request expires
total_amountamountTotal amount of the cooperative exit
{
  "type": "SPARK_COOP_EXIT_FINISHED",
  "id": "0194c7a2-5e1b-7c3d-9f00-3a1b2c4d5e6f",
  "created_at": "2026-01-15T14:32:00Z",
  "updated_at": "2026-01-15T14:32:00Z",
  "network": "MAINNET",
  "request_status": "SUCCEEDED",
  "status": "SUCCEEDED",
  "fee": {
    "value": 500,
    "unit": "SATOSHI"
  },
  "withdrawal_address": "bc1qtest...",
  "l1_broadcast_fee": {
    "value": 250,
    "unit": "SATOSHI"
  },
  "exit_speed": "MEDIUM",
  "coop_exit_txid": "0000000000000000000000000000000000000000000000000000000000000000",
  "expires_at": "2026-01-16T14:32:00Z",
  "total_amount": {
    "value": 200000,
    "unit": "SATOSHI"
  },
  "timestamp": "2026-01-15T14:32:00Z"
}

Static deposit finished

FieldTypeDescription
statusstringA ClaimStaticDepositStatus value: CREATED, TRANSFER_CREATED, TRANSFER_CREATION_FAILED, TRANSFER_COMPLETED, UTXO_SWAPPING_FAILED, SPEND_TX_CREATED, SPEND_TX_BROADCAST, SPEND_TX_CONFIRMED
deposit_amountamountAmount of the deposit
credit_amountamountAmount to be credited to the wallet
max_feeamountMaximum fee the wallet agreed to pay
transaction_idstringId of the deposit transaction
output_indexintegerIndex of the deposit output in that transaction
bitcoin_networkstringNetwork of the deposit: MAINNET, REGTEST, SIGNET or TESTNET
static_deposit_addressstring | nullStatic deposit address that received the deposit
{
  "type": "SPARK_STATIC_DEPOSIT_FINISHED",
  "id": "0194c7a2-5e1b-7c3d-9f00-3a1b2c4d5e6f",
  "created_at": "2026-01-15T14:32:00Z",
  "updated_at": "2026-01-15T14:32:00Z",
  "network": "MAINNET",
  "request_status": "SUCCEEDED",
  "status": "TRANSFER_COMPLETED",
  "deposit_amount": {
    "value": 300000,
    "unit": "SATOSHI"
  },
  "credit_amount": {
    "value": 299500,
    "unit": "SATOSHI"
  },
  "max_fee": {
    "value": 500,
    "unit": "SATOSHI"
  },
  "transaction_id": "0000000000000000000000000000000000000000000000000000000000000000",
  "output_index": 0,
  "bitcoin_network": "MAINNET",
  "static_deposit_address": "bc1qtest...",
  "timestamp": "2026-01-15T14:32:00Z"
}

Registering a webhook

To register a webhook, provide a URL, a secret for payload verification, and the event types you want to subscribe to.

Rust
let response = sdk
    .register_webhook(RegisterWebhookRequest {
        url: "https://example.com/webhook".to_string(),
        secret: "your-webhook-secret".to_string(),
        event_types: vec![
            WebhookEventType::LightningReceiveFinished,
            WebhookEventType::LightningSendFinished,
        ],
    })
    .await?;
info!("Webhook registered with ID: {}", response.webhook_id);
Swift
let response = try await sdk.registerWebhook(
    request: RegisterWebhookRequest(
        url: "https://example.com/webhook",
        secret: "your-webhook-secret",
        eventTypes: [.lightningReceiveFinished, .lightningSendFinished]
    ))
print("Webhook registered with ID: \(response.webhookId)")
Kotlin
val response = sdk.registerWebhook(RegisterWebhookRequest(
    url = "https://example.com/webhook",
    secret = "your-webhook-secret",
    eventTypes = listOf(
        WebhookEventType.LightningReceiveFinished,
        WebhookEventType.LightningSendFinished
    )
))
// Log.v("Breez", "Webhook registered with ID: ${response.webhookId}")
C#
var response = await sdk.RegisterWebhook(request: new RegisterWebhookRequest(
    url: "https://example.com/webhook",
    secret: "your-webhook-secret",
    eventTypes: new WebhookEventType[]
    {
        new WebhookEventType.LightningReceiveFinished(),
        new WebhookEventType.LightningSendFinished()
    }
));
Console.WriteLine($"Webhook registered with ID: {response.webhookId}");
Javascript
const response = await sdk.registerWebhook({
  url: 'https://example.com/webhook',
  secret: 'your-webhook-secret',
  eventTypes: [{ type: 'lightningReceiveFinished' }, { type: 'lightningSendFinished' }]
})
console.log(`Webhook registered with ID: ${response.webhookId}`)
React Native
const response = await sdk.registerWebhook({
  url: 'https://example.com/webhook',
  secret: 'your-webhook-secret',
  eventTypes: [
    new WebhookEventType.LightningReceiveFinished(),
    new WebhookEventType.LightningSendFinished()
  ]
})
console.log(`Webhook registered with ID: ${response.webhookId}`)
Flutter
RegisterWebhookRequest request = RegisterWebhookRequest(
  url: "https://example.com/webhook",
  secret: "your-webhook-secret",
  eventTypes: [
    WebhookEventType.lightningReceiveFinished(),
    WebhookEventType.lightningSendFinished(),
  ],
);
RegisterWebhookResponse response = await sdk.registerWebhook(request: request);
print("Webhook registered with ID: ${response.webhookId}");
Python
event_types = [
    WebhookEventType.LIGHTNING_RECEIVE_FINISHED(),
    WebhookEventType.LIGHTNING_SEND_FINISHED(),
]
response = await sdk.register_webhook(
    request=RegisterWebhookRequest(
        url="https://example.com/webhook",
        secret="your-webhook-secret",
        event_types=event_types,
    )
)
logging.debug(f"Webhook registered with ID: {response.webhook_id}")
Go
response, err := sdk.RegisterWebhook(breez_sdk_spark.RegisterWebhookRequest{
	Url:    "https://example.com/webhook",
	Secret: "your-webhook-secret",
	EventTypes: []breez_sdk_spark.WebhookEventType{
		breez_sdk_spark.WebhookEventTypeLightningReceiveFinished{},
		breez_sdk_spark.WebhookEventTypeLightningSendFinished{},
	},
})
if err != nil {
	return nil, err
}

log.Printf("Webhook registered with ID: %v", response.WebhookId)

Unregistering a webhook

To stop receiving notifications for a webhook, unregister it using its ID.

Rust
let webhook_id = "webhook-id".to_string();
sdk.unregister_webhook(UnregisterWebhookRequest { webhook_id })
    .await?;
info!("Webhook unregistered");
Swift
let webhookId = "webhook-id"
try await sdk.unregisterWebhook(
    request: UnregisterWebhookRequest(webhookId: webhookId))
print("Webhook unregistered")
Kotlin
val webhookId = "webhook-id"
sdk.unregisterWebhook(UnregisterWebhookRequest(webhookId = webhookId))
// Log.v("Breez", "Webhook unregistered")
C#
var webhookId = "webhook-id";
await sdk.UnregisterWebhook(request: new UnregisterWebhookRequest(
    webhookId: webhookId
));
Console.WriteLine("Webhook unregistered");
Javascript
const webhookId = 'webhook-id'
await sdk.unregisterWebhook({ webhookId })
console.log('Webhook unregistered')
React Native
const webhookId = 'webhook-id'
await sdk.unregisterWebhook({ webhookId })
console.log('Webhook unregistered')
Flutter
String webhookId = "webhook-id";
await sdk.unregisterWebhook(
  request: UnregisterWebhookRequest(webhookId: webhookId),
);
print("Webhook unregistered");
Python
webhook_id = "webhook-id"
await sdk.unregister_webhook(
    request=UnregisterWebhookRequest(webhook_id=webhook_id)
)
logging.debug("Webhook unregistered")
Go
webhookId := "webhook-id"
err := sdk.UnregisterWebhook(breez_sdk_spark.UnregisterWebhookRequest{
	WebhookId: webhookId,
})
if err != nil {
	return err
}

log.Printf("Webhook unregistered")

Listing webhooks

To retrieve all currently registered webhooks, use the list method.

Rust
let webhooks = sdk.list_webhooks().await?;
for webhook in webhooks {
    info!(
        "Webhook: id={}, url={}, events={:?}",
        webhook.id, webhook.url, webhook.event_types
    );
}
Swift
let webhooks = try await sdk.listWebhooks()
for webhook in webhooks {
    print("Webhook: id=\(webhook.id), url=\(webhook.url), events=\(webhook.eventTypes)")
}
Kotlin
val webhooks = sdk.listWebhooks()
for (webhook in webhooks) {
    // Log.v("Breez", "Webhook: id=${webhook.id}, url=${webhook.url}, events=${webhook.eventTypes}")
}
C#
var webhooks = await sdk.ListWebhooks();
foreach (var webhook in webhooks)
{
    Console.WriteLine($"Webhook: id={webhook.id}, url={webhook.url}, events={webhook.eventTypes}");
}
Javascript
const webhooks = await sdk.listWebhooks()
for (const webhook of webhooks) {
  console.log(`Webhook: id=${webhook.id}, url=${webhook.url}, events=${String(webhook.eventTypes)}`)
}
React Native
const webhooks = await sdk.listWebhooks()
for (const webhook of webhooks) {
  console.log(`Webhook: id=${webhook.id}, url=${webhook.url}, events=${String(webhook.eventTypes)}`)
}
Flutter
List<Webhook> webhooks = await sdk.listWebhooks();
for (Webhook webhook in webhooks) {
  print("Webhook: id=${webhook.id}, url=${webhook.url}, events=${webhook.eventTypes}");
}
Python
webhooks = await sdk.list_webhooks()
for webhook in webhooks:
    logging.debug(
        f"Webhook: id={webhook.id}, url={webhook.url}, "
        f"events={webhook.event_types}"
    )
Go
webhooks, err := sdk.ListWebhooks()
if err != nil {
	return nil, err
}

for _, webhook := range webhooks {
	log.Printf("Webhook: id=%v, url=%v, events=%v", webhook.Id, webhook.Url, webhook.EventTypes)
}