This project is not maintained anymore. And therefore was archived.
LaravelBtcPay enables you and your business to transact in Bitcoin, Litecoin and 10+ other BtcPay-supported cryptocurrencies within your Laravel application.
Requires PHP ^7.3
- ✅ Invoices
You can install the package via composer:
composer require petzsch/laravel-btcpay
Publish config file with:
php artisan vendor:publish --provider="Petzsch\LaravelBtcpay\LaravelBtcpayServiceProvider"
This will create a laravel-btcpay.php
file inside your config directory.
Add the following keys to your .env
file and update the values to match your
preferences (read more about configuration):
BTCPAY_API_KEY=YourRandomApiKeyThatYouOptainedFromYourBTCPayUserSettings
BTCPAY_SERVER_URL=https://btcpay.your.server.tld
BtcPay resource status updates are completely based on webhooks (IPNs). LaravelBtcPay is fully capable of automatically
handling webhook requests. Whenever a webhook is received from BtcPay's server, BtcpayWebhookReceived
event is
dispatched. Take the following steps to configure your application for webhook listening:
Resolve the btcPayWebhook
route macro in your desired route file (web.php
is recommended). The macro accepts a
single, optional argument, which is the URI path at which you want to receive BtcPay webhook POST
requests. If none is
provided, it defaults to 'laravel-btcpay/webhook'
:
// ... your other 'web' routes
Route::btcPayWebhook(); // https://example.com/laravel-btcpay/webhook
// OR ...
Route::btcPayWebhook('receive/webhooks/here'); // https://example.com/receive/webhooks/here
ℹ️ To retrieve your newly created webhook route anywhere in your application, use:
route('laravel-btcpay.webhook.capture')
LaravelBtcPay also offers the convenience of auto-populating your configured webhook url on applicable resources. Specifically when:
You may enable this feature per-resource by uncommenting the respective entry within the auto_populate_webhook
array
found in the laravel-btcpay.php
config file.
$resource->setNotificationURL('https://...')
during resource
initialization, auto-population is overridden.
Start by generating an event listener:
php artisan make:listener BtcPayWebhookListener --event=\Petzsch\LaravelBtcpay\Events\BtcpayWebhookReceived
Then, implement your application-specific logic in the handle(...)
function of the generated listener.
In the following example, we assume you have previously created an invoice, storing its token
on your internal Order
model:
/**
* Handle the webhook event, keeping in mind that the server doesn't trust the client (us), so neither should
* we trust the server. Well, trust, but verify.
*
* @param BtcpayWebhookReceived $event
* @return void
*/
public function handle(BtcpayWebhookReceived $event)
{
// Extract event payload
$payload = $event->payload;
// Verify that webhook is for a BtcPay Invoice resource
if (in_array($payload['event']['code'], array_keys(BtcPayConstants::INVOICE_WEBHOOK_CODES))) {
try {
// Do not trust the webhook data. Pull the referenced Invoice from BtcPay's server
$invoice = LaravelBtcpay::getInvoice($payload['data']['id']);
// Now grab our internal Order instance for this supposed Invoice
$order = Order::whereOrderId($invoice->getOrderId())->first();
// Verify Invoice token, previously stored at time of creation
// Learn more at: https://github.com/petzsch/laravel-btcpay#create-an-invoice
if ($invoice->getToken() !== $order->invoice_token) {
return;
}
$invoice_status = $invoice->getStatus();
// Do something about the new Invoice status
if ($invoice_status === InvoiceStatus::Paid) {
$order->update(['status' => $invoice_status]) && OrderStatusChanged::dispatch($order->refresh());
}
} catch (BtcPayException $e) {
Log::error($e);
}
}
}
Finally, map your listener to the BtcpayWebhookReceived
event inside the $listen
array of
your EventServiceProvider
:
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
// ... other event-listener mappings
BtcpayWebhookReceived::class => [
BtcPayWebhookListener::class,
],
]
Invoices are time-sensitive payment requests addressed to specific buyers. An invoice has a fixed price, typically denominated in fiat currency. It also has an equivalent price in the supported cryptocurrencies, calculated by BtcPay, at a locked exchange rate with an expiration time of 15(or whatever you configured) minutes.
In this example we assume you've already created an instance of your equivalent Order
model, to be associated with
this Invoice (referred to as $order
):
TODO: Check if all of this works with the invoice object exposed by greenfield!!!
// Create instance of Invoice
$invoice = LaravelBtcpay::Invoice(449.99, 'USD');
// Set item details (Only 1 item per Invoice)
$invoice->setItemDesc('You "Joe Goldberg" Life-Size Wax Figure');
$invoice->setItemCode('sku-1234');
$invoice->setPhysical(true); // Set to false for digital/virtual items
// Ensure you provide a unique OrderId for each Invoice
$invoice->setOrderId($order->order_id);
// Create Buyer Instance
$buyer = LaravelBtcpay::Buyer();
$buyer->setName('John Doe');
$buyer->setEmail('[email protected]');
$buyer->setAddress1('2630 Hegal Place');
$buyer->setAddress2('Apt 42');
$buyer->setLocality('Alexandria');
$buyer->setRegion('VA');
$buyer->setPostalCode(23242);
$buyer->setCountry('US');
$buyer->setNotify(true); // Instructs BtcPay to email Buyer about their Invoice
// Attach Buyer to Invoice
$invoice->setBuyer($buyer);
// Set URL that Buyer will be redirected to after completing the payment, via GET Request
$invoice->setRedirectURL(route('your-btcpay-success-url'));
// Set URL that Buyer will be redirected to after closing the invoice or after the invoice expires, via GET Request
$invoice->setCloseURL(route('your-btcpay-cancel-url'));
$invoice->setAutoRedirect(true);
// Optional. Learn more at: https://github.com/vrajroham/laravel-btcpay#1-setup-your-webhook-route
$invoice->setNotificationUrl('https://example.com/your-custom-webhook-url');
// This is the recommended IPN format that BtcPay advises for all new implementations
$invoice->setExtendedNotifications(true);
// Create invoice on BtcPay's server
$invoice = LaravelBtcpay::createInvoice($invoice);
$invoiceId = $invoice->getId();
$invoiceToken = $invoice->getToken();
// You should save Invoice ID and Token, for your reference
$order->update(['invoice_id' => $invoiceId, 'invoice_token' => $invoiceToken]);
// Redirect user to the Invoice's hosted URL to complete payment
// This could be done more elegantly with our JS modal!
$paymentUrl = $invoice->getUrl();
return Redirect::to($paymentUrl);
ℹ️ It is highly recommended you store the Invoice ID and Token on your internal model(s). The token can come in handy when verifying webhooks.
$invoice = LaravelBtcpay::getInvoice('invoiceId_sGsdVsgheF');
In this example we retrieve all MTD (Month-To-Date) invoices: TODO: unsupported by Greenfield!!!
$startDate = date('Y-m-d', strtotime('first day of this month'));
$endDate = date('Y-m-d');
$invoices = LaravelBtcpay::getInvoices($startDate, $endDate);
TODO: Add support for pull payments to implement refunds (not currently included)
composer test
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.