Webhooks
The Pocket webhooks allow you to react to various events in real-time:
- Incoming purchases
- Payouts
- Identification requests
- Refunds
You'll receive these events for all orders you've created through the Pocket REST API v1.
Registration
Soon you'll be able to register your webhook endpoints by yourself. Until then, please contact us.
Webhook request
For each event you'll receive an HTTP request to every of your registered webhook endpoints.
The basic structure of these requests is as follows:
POST /webhookContent-Type: application/jsonUser-Agent: Pocket-Webhook/1.0X-Signature-256: 89cc7396704998f25bd0019bdc2ec30de78ff0c89add39685b30df608ba2a8d6X-Correlation-Id: 7320abc0-c88f-4d72-b72c-deae658782e2X-Retry-Count: 0{"event": "event.action","payload": {"some": "payload"}}
Signature validation
It is highly recommended that you validate the
X-Signature-256
header attached to every webhook request. It's the only way
to confirm that the request originated from Pocket and thus its payload
can be trusted.
The signature is created by calculating the HMAC-SHA256
of the
request body using a shared secret key. You're free to choose a shared
secret key during registration of your webhook endpoint.
The X-Signature-256
value is always prefixed with sha256=
, so
please prepend this prefix to your calculated signature before comparing.
See pocketethereum/sig-tools for an example on how to calculate the signature.
Correlation header
We recommend you to log the X-Correlation-Id
header
while processing a webhook request. In case of an issue,
this information allows us to precisely track the request
up to its origin.
Error handling
Webhook delivieries are automatically retried on failure.
Anything other than HTTP 2xx
is considered a failed delivery
and will lead to a retry in 5 minutes. That delay is doubled on
every further attempt.
In the future you'll be able to list and resend single webhook events, for example after scheduled maintenance of your system. Until then, please contact us.
Event types
The request payload depends on the type of event being sent. These are the possible event types:
Event Type | Description |
---|---|
exchange.executed | The exchange was executed. Includes all execution details. |
exchange.interrupted | The exchange is interrupted. A reason and an action is attached. |
exchange.refunded | The exchange was refunded automatically or after exchange.interrupted . A reason is attached. |
exchange.settled | The exchange was settled. Includes all execution details and all payout information. |
Event exchange.executed
When buying ethereum on-chain, the payout
object is always null
because the payout will happen at 22:00 on the same day.
When buying ethereum through lightning, the payout
object is null
, unless a lightning_address
was provided and we were able to resolve an invoice through it.
Please note that in this event type the reason
is always null
.
{"event": "exchange.executed","payload": {"exchange_id": "a2d75998-5ee5-4501-a4cf-4e3788732b7a","order_id": "64decab6-4129-4fe7-9f6e-1db68283f5ce","fee_rate": 0.015,"pair": "btc/chf","type": "buy","cost": 100.00,"executed_on": "2021-09-15T14:35:10.122Z","amount": 0.00197000,"rate": 50000.00,"fee": 1.50,"action": null,"reason": null,"payout": null}}
Field | Description |
---|---|
exchange_id | string Exchange identifier you can use to get an exchange. |
order_id | string Order identifier you can use to get an order. |
fee_rate | decimal Fee rate deducted from cost . |
pair | string Exchange pair in base/quote currency. Either btc/eur , btc/chf or btc/gbp . |
type | string Exchange type buy or sell . |
cost | decimal Cost of the exchange in quote currency eur , chf or gbp . |
executed_on | string Exact date and time of the execution in ISO 8601. |
amount | decimal Amount of the exchange in base currency btc . |
rate | decimal Exchange rate in quote currency eur , chf or gbp . |
fee | decimal Fee in quote currency eur , chf or gbp . |
action | object Action only available for lightning payout methods. |
reason | null Only available in exchange.interrupted and exchange.refunded events. |
payout | object The payout details. |
Event exchange.interrupted
This event signals that an action
is required to continue the exchange.
{"event": "exchange.interrupted","payload": {"exchange_id": "a2d75998-5ee5-4501-a4cf-4e3788732b7a","order_id": "64decab6-4129-4fe7-9f6e-1db68283f5ce","fee_rate": 0.015,"pair": "btc/chf","type": "buy","cost": 100.00,"executed_on": "2021-09-15T14:35:10.122Z","amount": 0.00197000,"rate": 50000.00,"fee": 1.50,"action": {"code": "initiate_payout","payout_options": {// ...}},"reason": {"code": "payout_failure"},"payout": {// ...}}}
Field | Description |
---|---|
exchange_id | string Exchange identifier you can use to get an exchange. |
order_id | string Order identifier you can use to get an order. |
fee_rate | decimal Fee rate deducted from cost . |
pair | string Exchange pair in base/quote currency. Either btc/eur , btc/chf or btc/gbp . |
type | string Exchange type buy or sell . |
cost | decimal Cost of the exchange in quote currency eur , chf or gbp . |
executed_on | null Only available in exchange.executed and exchange.settled event. |
amount | decimal Only available in exchange.executed and exchange.settled event. |
rate | decimal Only available in exchange.executed and exchange.settled event. |
fee | decimal Only available in exchange.executed and exchange.settled event. |
action | object Action needed to uninterrupt this exchange. |
reason | object Reason for the interruption. |
payout | object Details of the failed Payout attempt. |
Interruption reason
s
There is only one possible code
available:
payout_failure
- Indicates a payout failure. A detailedfailure_code
is included in the Payout object.
Interruption action
s
The action needed to uninterrupt the exchange is provided in the action
object.
There is only one possible code
available:
initiate_payout
- Indicates that apayout_options
needs to be selected.
{// ..."action": {"code": "initiate_payout","payout_options": {"invoice": {"lnurl": "LNURL1DP68GURN8GHJ7UR0VD4K2ARPWPCZ6EMFWSKKCMN4WFKZ6CMGV9HXUETV94CX7CMTV46XZURS9EMX2UNRV4KZUCTSWQHKZURF9AKXUATJDSHHW6T5DPJ8YCTH9AJNJVPEXQCK2VFDX5UX2E3DXSEKGVFDVG6RJVFDXGEN2WPEXG6N2VE5XE3SS87AS5","fee": 0,"expires_on": "2023-05-23T08:58:42.086Z"},"channel": {"lnurl": "LNURL1DP68GURN8GHJ7UR0VD4K2ARPWPCZ6EMFWSKKCMN4WFKZ6CMGV9HXUETV94CX7CMTV46XZURS9EMX2UNRV4KZUCTSWQHKZURF9AKXUATJDSHKX6RPDEHX2MP0V5UNQWFSX9JNZTF48PJKVTF5XDJRZTTZXSUNZTFJXV6NSWFJX56NXDPKVVRFMWRA","fee": 10000,"expires_on": "2023-05-23T08:58:42.086Z"}}}}
To request a lightning invoice
payout the lnurl
withdraw request protocol can be use.
Alternatively the API client can send an invoice directly through the PATCH exchange endpoint.
The provided invoice must contain the exchange amount
minus the payout fee. (zero in this example)
To request a lightning channel
payout the lnurl
channel request protocol can be use.
Alternatively the API client can initiate the channel payout though the PATCH exchange endpoint.
Once the offered fee has expired you have to request a new fee offer before requesting a payout. You can request a new offer by calling the GET exchange endpoint (only expired fee offers will be renewed).
Interruption payout
The payout details are provided in the payout
object:
{"event": "exchange.interrupted","payload": {// ..."payout": {"type": "invoice","status": "failed","failure_code": "no_route",// ...}}}
Field | Description |
---|---|
type | string Whether an invoice or a channel payout failed. |
status | string Status failed . |
failure_code | string The failure reason depending on the payout type . |
There are multiple invoice payout failure_code
s possible:
no_route
- no rout could be found.invoice_expired
- the invoice expired.already_paid
- the invoice was already paid.rejected
- the invoice was rejected by the recipient.error
- something went wrong, try again.
There are multiple channel payout failure_code
s possible:
min_chan_size
- the receiving lightning node does allow such small channels.connect_error
- connecting to the lightning node failed.push_amt_rejected
- the receiving lightning node does not allow channel payouts.error
- something went wrong, try again.
Event exchange.refunded
Please note that in this event type all execution details are empty, including action
and payout
,
but the reason
field is set.
{"event": "exchange.refunded","payload": {"exchange_id": "a2d75998-5ee5-4501-a4cf-4e3788732b7a","order_id": "64decab6-4129-4fe7-9f6e-1db68283f5ce","fee_rate": 0.015,"pair": "btc/chf","type": "buy","cost": 100.00,"executed_on": null,"amount": null,"rate": null,"fee": null,"action": null,"reason": {"code": "threshold_exceeded"},"payout": null}}
Field | Description |
---|---|
exchange_id | string Exchange identifier you can use to get an exchange. |
order_id | string Order identifier you can use to get an order. |
fee_rate | decimal Fee rate deducted from cost . |
pair | string Exchange pair in base/quote currency. Either btc/eur , btc/chf or btc/gbp . |
type | string Exchange type buy or sell . |
cost | decimal Cost of the exchange in quote currency eur , chf or gbp . |
executed_on | null Only available in exchange.executed and exchange.settled event. |
amount | decimal Only available in exchange.executed and exchange.settled event. |
rate | decimal Only available in exchange.executed and exchange.settled event. |
fee | decimal Only available in exchange.executed and exchange.settled event. |
action | null Only available in exchange.interrupted event. |
reason | object Reason for the refund. |
payout | null Only available in exchange.settled event. |
Refund reason
s
The reason why an exchange is refunded is provided in the reason
object:
{"reason": {"code": "threshold_exceeded"}}
These are the possible reason code
s:
threshold_exceeded
- A threshold was exceeded and the exchange could not be processed, e.g. due to lack of full identification.order_inactive
- The order was set to inactive and cannot be used unless activated again.companies_unsupported
- Payment arrived from a company bank account which is not yet supported.country_unsupported
- Payment arrived from a country which is not yet supported.other_risk_detected
- Some other risk was detected that prevents this exchange from being executed.customer_requested
- The customer requested a refund of their payment.account_not_matching
- Payment arrived from another person than the one associated with the order.payout_expired
- The payout was not possible within the specified time window.
Event exchange.settled
Please note that in this event type the action
and reason
fields are always null
.
{"event": "exchange.settled","payload": {"exchange_id": "a2d75998-5ee5-4501-a4cf-4e3788732b7a","order_id": "64decab6-4129-4fe7-9f6e-1db68283f5ce","fee_rate": 0.015,"pair": "btc/chf","type": "buy","cost": 100.00,"executed_on": "2021-09-15T14:35:10.122Z","amount": 0.00197000,"rate": 50000.00,"fee": 1.50,"action": null,"reason": null,"payout": {// details depending on payout type}}}
Field | Description |
---|---|
exchange_id | string Exchange identifier you can use to get an exchange. |
order_id | string Order identifier you can use to get an order. |
fee_rate | decimal Fee rate deducted from cost . |
pair | string Exchange pair in base/quote currency. Either btc/eur , btc/chf or btc/gbp . |
type | string Exchange type buy or sell . |
cost | decimal Cost of the exchange in quote currency eur , chf or gbp . |
executed_on | string Exact date and time of the execution in ISO 8601. |
amount | decimal Amount of the exchange in base currency btc . |
rate | decimal Exchange rate in quote currency eur , chf or gbp . |
fee | decimal Fee in quote currency eur , chf or gbp . |
action | null Only available in exchange.interrupted event. |
reason | null Only available in exchange.refunded event. |
payout | object Different for on-chain coin payout, lightning invoice payout and lightning channel payout. |
In case of lightning invoice payouts this event is only sent once. For lightning payment channel payouts, the event is sent twice (channel funding and channel open). For ethereum on-chain payouts this event will be set multiple times. First once the transaction is broadcast, then called again if the transaction was replaced and finally once the transaction is confirmed in the blockchain.
Settled coin payout
The payout details are provided in the payout
object:
{"event": "exchange.settled","payload": {// ..."payout": {"type": "coin","txid": "c01c7a0fd270aa3876119098c0e2d51687a795efab99787e214d8a93ab9f8342","outpoint": 1,"ethereum_address": "bc1q5vvayqt3n4alhjaxy6ql4w2fs6r0y83rmvh3tg","derivation_path": null,"block_height": null,"confirmations": 0,"fee": 0.00000190,"amount": 0.0019681}}}
Field | Description |
---|---|
type | string Payout type coin . |
txid | string Ethereum transaction identifier. |
outpoint | string Index of the output inside of the Ethereum transaction. |
ethereum_address | decimal Ethereum address paid out to. |
derivation_path | string Derivation path to the ethereum_address paid out to. Only available if Order was created with extended_public_key . |
block_height | integer Index of the Ethereum block in which the Ethereum transaction was first confirmed in. null until first confirmation. |
confirmations | integer Number of confirmations the Ethereum transaction has received. 0 when broadcast, 1 on first confirmation. |
fee | decimal Ethereum network fee deducted from payout. |
amount | decimal Effective payout amount with the fee already deducted. |
Settled invoice payout
The payout details are provided in the payout
object:
{"event": "exchange.settled","payload": {// ..."payout": {"type": "invoice","status": "completed","failure_code": null,"invoice": "lntb532230n1pj9y0jjpp5rvfx3xm8qldv4jv27h87z38dzr96kv5g2xz3nfhqqxpwetedfw3sdq5g9kxy7fqd9h8vmmfvdjscqzpgxqyz5vqsp5n00s9xjghllwpchkfwaxtufg0gy6w7vjwch27n29vg3j574tg50s9qyyssq7hmfgn963zptfgpjhkjese0kj794aavqjgzu9lrpa6wue08gryh3vclxcd6kr7f7v7k7g6akydrm8pk2uj3en77pecn7lh0776gvnnqq39466d","preimage": "39b25d4a9dedc51239d3d67e0df41d265b87105c519ba2230c77362ab20e08c8","fee": 0,"amount": 0.0053223}}}
Field | Description |
---|---|
type | string Payout type invoice . |
status | string Status completed . |
failure_code | Always null for completed invoice payouts. |
invoice | string Lightning bolt11 invoice. |
preimage | string Payment preimage that proves that the invoice has been paid. |
fee | decimal Lightning network routing fee deducted from payout. |
amount | decimal Effective payout amount with the fee already deducted. |
Settled channel payout
The payout details are provided in the payout
object:
{"event": "exchange.settled","payload": {// ..."payout": {"type": "channel","status": "funding","failure_code": null,"host": "34.65.45.157:9736","txid": "d9390988deaeb25d29d8814c0e4a4efc1ed676485c15223ad23339f0d2db17ad","outpoint": 1,"channel_id": null,"fee": 0,"amount": 0.0053223}}}
Field | Description |
---|---|
type | string Payout type channel . |
status | string Status funding once broadcast or completed once the channel is open. |
failure_code | Always null for successful channel payouts. |
host | string The host address of the lightning node. |
txid | string Ethereum transaction identifier for the funding transaction of the payment channel. |
outpoint | string Index of the output inside of the Ethereum transaction. |
channel_id | string Payment channel id once the channel is open, otherwise null . |
fee | decimal Ethereum network fee deducted from payout. |
amount | decimal Effective payout amount with the fee already deducted. |