Resources
Resource | Description |
---|---|
Challenge | A one-time challenge required in the signed message when creating an order. |
Order | A long-living order holding payment and payout instructions. |
Exchange | An exchange initiated by funding a previously created order. |
Download our Postman Collection to find examples on how to work with these resources.
Exchange pairs
Pair | Base currency | Quote currency |
---|---|---|
btc/eur | btc | eur |
btc/chf | btc | chf |
btc/gbp | btc | gbp |
Please note that cost
, rate
and fee
are always denominated in the quote currency eur
, chf
or gbp
,
while the amount
is denominated in the base currency btc
.
Exchange types
Type | Description |
---|---|
buy | Buy base currency btc for quote currency eur , chf or gbp . |
sell | Sell base currency btc for quote currency eur , chf or gbp . |
Proof of ownership
Pocket needs to make sure that the addresses it pays out to are controlled by its users themselves.
It does this by requesting a signature that can only be produced with the private key of the receiving address.
The message that is signed can be chosen freely but must contain a previously generated Challenge
token.
The same signature requirement applies to lightning payout_method
s.
Affiliation
All orders created through your api client automatically get affiliated to you.
This means that part of the fees is attributed and paid out to you, according to the conditions
defined during registration. If you have multiple agreements, you can use the optional
affiliate_id
field to choose which affiliate agreement to use.
Create a challenge
You'll need to create a challenge before you can create a new order. Its random token will have to be included in the message to be signed.
POST /v1/challenges{}
201
created challenge
{"id": "95ab94f0-bd8d-410c-bfc8-b1f27d43b0c0","token": "7v7t4Fmb","expires_on": "2022-01-10T00:25:11.123Z","completed_on": null}
Get a challenge
Although unlikely, if you ever need to retrieve a previously created challenge
using your client_id
, you can do that very simply.
GET /v1/challenges/{id}
200
existing challenge
{"id": "95ab94f0-bd8d-410c-bfc8-b1f27d43b0c0","token": "7v7t4Fmb","expires_on": "2022-01-10T00:25:11.123Z","completed_on": null}
Create an order
An order is a long-living set of a payment and payout instructions.
You create it once and it can be used for one-time Bitcoin purchases, but also
for standing orders. The order also allows you to define the fee_rate
applied
to all exchanges (1.2% - 4.5%).
POST /v1/orders{"active": true,"affiliate_id": "8ed13c2a-a8c6-4f0e-b43e-3fdbf1f094a6", // optional"fee_rate": 0.03,"payment_method": {"currency": "chf","debitor_iban": "DE75512108001245126199"},"payout_method": {"bitcoin_address": "17wvJajWQjoVJuJe31tuiDs4MmVeBfSvGY","message": "I confirm my bitcoin wallet. [7v7t4Fmb]","signature": "IKiJsfsAta7Id7Seq+j8EEfpFUj2LCVDRjQ+ZC3/akv+VfUznwmq9mkxQtvqz8NTr0t6VnmTBcsEhHLMQYixHZM="}}
201
created order
{"id": "64decab6-4129-4fe7-9f6e-1db68283f5ce","active": true,"created_on": "2021-09-10T04:55:36.887Z","affiliate_id": "8ed13c2a-a8c6-4f0e-b43e-3fdbf1f094a6","fee_rate": 0.03,"payment_method": {"currency": "chf","debitor_iban": "DE75512108001245126199","creditor_reference": "RF18GW8K79","creditor_iban": "CH9400778214768302002","creditor_bank_name": "Luzerner Kantonalbank","creditor_bank_street": "Pilatusstrasse 12","creditor_bank_postal_code": "6002","creditor_bank_town": "Luzern","creditor_bank_country": "CH","creditor_bank_bic": "LUKBCH2260A","creditor_name": "Pocket App","creditor_street": "Industriestrasse 33","creditor_postal_code": "5242","creditor_town": "Lupfig","creditor_country": "CH","swiss_qr_bill_payload": null},"payout_method": {"bitcoin_address": "17wvJajWQjoVJuJe31tuiDs4MmVeBfSvGY","message": "I confirm my bitcoin wallet. [7v7t4Fmb]","signature": "IKiJsfsAta7Id7Seq+j8EEfpFUj2LCVDRjQ+ZC3/akv+VfUznwmq9mkxQtvqz8NTr0t6VnmTBcsEhHLMQYixHZM="}}
Extended public key
To prevent address reuse when re-using an order, the payout method can be
extended with the extended_public_key
. The derivation_path
is also
required to identify the location of the bitcoin_address
. This allows Pocket to
derive a fresh unused address for every payout.
{// ..."payout_method": {"bitcoin_address": "17wvJajWQjoVJuJe31tuiDs4MmVeBfSvGY","message": "I confirm my bitcoin wallet. [7v7t4Fmb]","signature": "IKiJsfsAta7Id7Seq+j8EEfpFUj2LCVDRjQ+ZC3/akv+VfUznwmq9mkxQtvqz8NTr0t6VnmTBcsEhHLMQYixHZM=","extended_public_key": "xpub6C9cxxj5hCqTY7sYeofQPA4nXuLJpL5xBL5F874n8hremDiwrWPsPBmxjJxHqBL7jwxKy33j4uJmHXQSNxRegEY2MukehJUe8s4mBkaFGBU","derivation_path": "0/1","gap_limit": null // default 10}}
201
created order
{// ..."payout_method": {"bitcoin_address": "17wvJajWQjoVJuJe31tuiDs4MmVeBfSvGY","message": "I confirm my bitcoin wallet. [7v7t4Fmb]","signature": "IKiJsfsAta7Id7Seq+j8EEfpFUj2LCVDRjQ+ZC3/akv+VfUznwmq9mkxQtvqz8NTr0t6VnmTBcsEhHLMQYixHZM=","extended_public_key": "xpub6C9cxxj5hCqTY7sYeofQPA4nXuLJpL5xBL5F874n8hremDiwrWPsPBmxjJxHqBL7jwxKy33j4uJmHXQSNxRegEY2MukehJUe8s4mBkaFGBU","derivation_path": "0/1","gap_limit": null}}
Lightning payout method beta
Apart from an on-chain payout method, you can also configure your order's exchanges to be
paid out through Lightning, by specifying your node_pubkey
.
{// ..."payout_method": {"node_pubkey": "02765a281bd188e80a89e6ea5092dcb8ebaaa5c5da341e64327e3fadbadcbc686c","message": "I confirm my bitcoin wallet. [7v7t4Fmb]","signature": "rywfek6717yuqpfpjmghyf173obgswr9uw5wbfsfhc8exjomftm71st4cyxprzkx5juxiokhbxm8rzkxoz8e3zmmpa644tudgt119s91",}}
201
created order
{// ..."payout_method": {"node_pubkey": "02765a281bd188e80a89e6ea5092dcb8ebaaa5c5da341e64327e3fadbadcbc686c","message": "I confirm my bitcoin wallet. [7v7t4Fmb]","signature": "rywfek6717yuqpfpjmghyf173obgswr9uw5wbfsfhc8exjomftm71st4cyxprzkx5juxiokhbxm8rzkxoz8e3zmmpa644tudgt119s91"}}
Patch an order
You can patch the active
and fee_rate
fields of an existing order
created with your client_id
at any time.
PATCH /v1/orders/{id}{"active": false, // optional"affiliate_id": "8ed13c2a-a8c6-4f0e-b43e-3fdbf1f094a6", // optional"fee_rate": 0.025 // optional}
200
patched order
{"id": "64decab6-4129-4fe7-9f6e-1db68283f5ce","active": false,"created_on": "2021-09-10T04:55:36.887Z","affiliate_id": "8ed13c2a-a8c6-4f0e-b43e-3fdbf1f094a6","fee_rate": 0.025,"payment_method": {"currency": "chf","debitor_iban": "DE75512108001245126199","creditor_reference": "RF18GW8K79","creditor_iban": "CH9400778214768302002","creditor_bank_name": "Luzerner Kantonalbank","creditor_bank_street": "Pilatusstrasse 12","creditor_bank_postal_code": "6002","creditor_bank_town": "Luzern","creditor_bank_country": "CH","creditor_bank_bic": "LUKBCH2260A","creditor_name": "Pocket App","creditor_street": "Industriestrasse 33","creditor_postal_code": "5242","creditor_town": "Lupfig","creditor_country": "CH","swiss_qr_bill_payload": null},"payout_method": {"bitcoin_address": "17wvJajWQjoVJuJe31tuiDs4MmVeBfSvGY","message": "I confirm my bitcoin wallet. [7v7t4Fmb]","signature": "IKiJsfsAta7Id7Seq+j8EEfpFUj2LCVDRjQ+ZC3/akv+VfUznwmq9mkxQtvqz8NTr0t6VnmTBcsEhHLMQYixHZM=","extended_public_key": "xpub6C9cxxj5hCqTY7sYeofQPA4nXuLJpL5xBL5F874n8hremDiwrWPsPBmxjJxHqBL7jwxKy33j4uJmHXQSNxRegEY2MukehJUe8s4mBkaFGBU","derivation_path": "0/1","gap_limit": null}}
Get an order
You can retrieve all orders created using your client_id
at any time.
GET /v1/orders/{id}
200
existing order
{"id": "64decab6-4129-4fe7-9f6e-1db68283f5ce","active": true,"created_on": "2021-09-10T04:55:36.887Z","affiliate_id": "8ed13c2a-a8c6-4f0e-b43e-3fdbf1f094a6","fee_rate": 0.03,"payment_method": {"currency": "chf","debitor_iban": "DE75512108001245126199","creditor_reference": "RF18GW8K79","creditor_iban": "CH9400778214768302002","creditor_bank_name": "Luzerner Kantonalbank","creditor_bank_street": "Pilatusstrasse 12","creditor_bank_postal_code": "6002","creditor_bank_town": "Luzern","creditor_bank_country": "CH","creditor_bank_bic": "LUKBCH2260A","creditor_name": "Pocket App","creditor_street": "Industriestrasse 33","creditor_postal_code": "5242","creditor_town": "Lupfig","creditor_country": "CH","swiss_qr_bill_payload": null},"payout_method": {"bitcoin_address": "17wvJajWQjoVJuJe31tuiDs4MmVeBfSvGY","message": "I confirm my bitcoin wallet. [7v7t4Fmb]","signature": "IKiJsfsAta7Id7Seq+j8EEfpFUj2LCVDRjQ+ZC3/akv+VfUznwmq9mkxQtvqz8NTr0t6VnmTBcsEhHLMQYixHZM=","extended_public_key": "xpub6C9cxxj5hCqTY7sYeofQPA4nXuLJpL5xBL5F874n8hremDiwrWPsPBmxjJxHqBL7jwxKy33j4uJmHXQSNxRegEY2MukehJUe8s4mBkaFGBU","derivation_path": "0/1","gap_limit": null}}
Get an exchange
You can retrieve all exchanges initiated by orders created using your client_id
at any time.
GET /v1/exchanges/{id}
200
executed 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}
200
interrupted 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": {"code": "identification_required","identification_id": "7bf967b5-3d34-4cd6-936c-6631811401d2"},"reason": null,"payout": null}
200
refunded 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}
200
settled 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": {"txid": "c01c7a0fd270aa3876119098c0e2d51687a795efab99787e214d8a93ab9f8342","outpoint": 1,"bitcoin_address": "bc1q5vvayqt3n4alhjaxy6ql4w2fs6r0y83rmvh3tg","derivation_path": null,"block_height": null,"confirmed": false,"fee": 0.00000190,"amount": 0.0019681}}
Patch an exchange beta
Exchanges created for lightning orders require additional instructions on how the exchanged bitcoin should be paid out.
The different payout options and fee conditions are included in the webhook exchange.executed
event payload.
Invoice payout
In case the receiving lightning node has enough inbound liquidity, this payout option is preferable.
PATCH /v1/exchanges/{id}{"payout": {"type": "invoice","invoice": "lnbcrt585180n1pjrucjgpp5n64x8ugk4tuz3wkjuuqkmvsgf9xetq8l4ntj7nsr373zpmd5yvdsdqqcqzpgxqyz5vqsp5dhxsdywke3fuz3fhcv79n7y00zdxqdhz8japmpx2hgk5pa92llxs9qyyssqtk0wr35e65yupmsnzp9n3r2ynqdv420kt9rnukwxwh744mmsusnn2600wpdfpcsx5r2cjsc0t5583fhrgcsejlqp7uept6tv0tnufdqp4jwez5"}}
200
patched 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": {"type": "invoice","status": "pending","invoice": "lnbcrt585180n1pjrucjgpp5n64x8ugk4tuz3wkjuuqkmvsgf9xetq8l4ntj7nsr373zpmd5yvdsdqqcqzpgxqyz5vqsp5dhxsdywke3fuz3fhcv79n7y00zdxqdhz8japmpx2hgk5pa92llxs9qyyssqtk0wr35e65yupmsnzp9n3r2ynqdv420kt9rnukwxwh744mmsusnn2600wpdfpcsx5r2cjsc0t5583fhrgcsejlqp7uept6tv0tnufdqp4jwez5","preimage": null,"fee": 0,"amount": 0.00197000}}
400
bad request
{"error": "unexpected_node_pubkey","documentation_uri": "https://pocketbitcoin.com/developers"}
Other bad request error
codes are:
in_progress
- the payout is already in progress.already_completed
- the payout is already completed.invoice_amount
- Invoice contains no or wrong amount.invoice_network
- Invoice for wrong bitcoin network.invoice_expired
- The invoice is expired.unexpected_node_pubkey
- Invoice from the wrong lightning node.invalid_invoice
- Invoice not valid.
Channel payout
In case the receiving node has not enough inbound liquidity, this payout method can be used to open a new payment channel.
The exchanged amount of bitcoin is paid out by leveraging the push_msat
field during channel negotiation (see BOLT 2).
PATCH /v1/exchanges/{id}{"payout": {"type": "channel","node_address": "02765a281bd188e80a89e6ea5092dcb8ebaaa5c5da341e64327e3fadbadcbc686c@34.65.45.157:9736" // optional"private": true // optional}}
200
patched 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": {"type": "channel","status": "pending","node_address": "02765a281bd188e80a89e6ea5092dcb8ebaaa5c5da341e64327e3fadbadcbc686c@34.65.45.157:9736","private": true,"txid": null,"outpoint": null,"channel_id": null,"fee": 0.0001,"amount": 0.00187000,}}
400
bad request
{"error": "connect","documentation_uri": "https://pocketbitcoin.com/developers"}
Other bad request error
codes are:
in_progress
- the payout is already in progress.already_completed
- the payout is already completed.channel_payout_not_allowed
- Channel payout is not allowed, a direct channel exists.node_address_required
- Unable to resolve the lightning node address. Please provide thenode_address
and try again.unexpected_node_pubkey
- Unexpected node pubkey in providednode_address
.connect
- Unable to connect to the lightning node.