How to Receive Crypto Payments in Laravel Using an API

·

This guide will walk you through building a payment gateway in Laravel that supports Tron (TRX) and JST (TRC20) cryptocurrency payments. You’ll learn how to generate wallet addresses for each payment session, handle transaction notifications via webhooks, and verify transaction statuses before processing orders.

By the end of this tutorial, you’ll have a functional payment system that interacts with blockchain networks through a secure API. The same approach can be adapted for other major cryptocurrencies like Bitcoin, Ethereum, Binance Smart Chain, and Polygon with minor adjustments.


Introduction

Integrating cryptocurrency payments into your Laravel application can streamline transactions and open up global payment opportunities. Using a dedicated blockchain API simplifies complex processes like address generation, transaction monitoring, and fund management.

Core Tools and Concepts

You’ll be using a blockchain API service to handle interactions with the Tron network. This allows you to:

👉 Explore real-time payment integration tools


Prerequisites

Before you begin, make sure you have the following:


Key Features of the Payment Gateway

The system you’ll build includes:


Step 1: API Configuration

Start by configuring your Laravel application to connect to the blockchain API.

Update Config Files

Add the API settings to your config/app.php file under the return array:

'BlockchainAPI' => [
    'api_url' => env('BLOCKCHAIN_API_URL', 'https://api.blockchainapi.io/api/v2'),
    'api_key' => env('BLOCKCHAIN_API_KEY'),
    'network' => env('BLOCKCHAIN_NETWORK', 'testnet'),
    'cold_wallet' => env('COLD_WALLET_ADDRESS'),
],

Next, update your .env file with your actual credentials:

BLOCKCHAIN_API_URL=https://api.blockchainapi.io/api/v2
BLOCKCHAIN_API_KEY=your_actual_api_key_here
BLOCKCHAIN_NETWORK=testnet
COLD_WALLET_ADDRESS=your_cold_wallet_address_here

Configuration Explanation


Step 2: Define Application Routes

Define the routes that handle payment sessions and webhooks in routes/web.php:

use App\Http\Controllers\PaymentController;

Route::get('/payment', [PaymentController::class, 'showPaymentPage']);
Route::post('/start-payment-session', [PaymentController::class, 'startPaymentSession']);
Route::get('/payment-session/{id}', [PaymentController::class, 'showPaymentSession'])->name('showPaymentSession');
Route::post('/webhook', [PaymentController::class, 'handleWebhook']);

Route Functions

Disable CSRF Protection for Webhooks

To allow external services to post to your webhook, disable CSRF protection for that route. In bootstrap/app.php:

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(...)
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->validateCsrfTokens(except: ['webhook']);
    })
    ->create();

Step 3: Create Models and Migrations

You’ll need two database tables to store wallet information and payment sessions.

Generate Models and Migrations

Run these Artisan commands:

php artisan make:model Wallet -m
php artisan make:model PaymentSession -m

Define Database Schema

In the wallets migration file:

Schema::create('wallets', function (Blueprint $table) {
    $table->id();
    $table->string('address')->unique();
    $table->string('private_key');
    $table->timestamps();
});

In the payment_sessions migration file:

Schema::create('payment_sessions', function (Blueprint $table) {
    $table->id();
    $table->string('status')->default('Pending');
    $table->foreignId('wallet_id')->constrained()->onDelete('cascade');
    $table->decimal('amount', 18, 8)->nullable();
    $table->string('currency')->default('TRX');
    $table->decimal('received_amount', 18, 8)->nullable();
    $table->string('webhook_id')->nullable();
    $table->timestamps();
});

Run the migrations:

php artisan migrate

Set Up Model Relationships

In app/Models/Wallet.php:

protected $fillable = ['address', 'private_key'];

public function paymentSessions()
{
    return $this->hasMany(PaymentSession::class);
}

In app/Models/PaymentSession.php:

protected $fillable = ['wallet_id', 'status', 'amount', 'currency', 'received_amount', 'webhook_id'];

public function wallet()
{
    return $this->belongsTo(Wallet::class);
}

Step 4: Build the Payment Controller

The controller handles the core logic: creating sessions, generating wallets, and processing webhooks.

Generate the controller:

php artisan make:controller PaymentController

Controller Method Overview

Key Functionality Details

The startPaymentSession method uses the API to generate a new wallet address and sets up a webhook for transaction alerts. The handleWebhook method verifies transactions by checking the blockchain receipt and updates the payment status accordingly. It includes logic to handle overpayments, underpayments, and currency mismatches.


Step 5: Create the Views

Payment Form Page

Create resources/views/payment.blade.php:

<!DOCTYPE html>
<html>
<head>
    <title>Start Payment</title>
</head>
<body>
    <h1>Start a New Payment Session</h1>
    <form action="/start-payment-session" method="POST">
        @csrf
        <label>Amount: <input type="number" name="amount" step="0.000001" required></label>
        <label>Currency:
            <select name="currency">
                <option value="TRX">TRX</option>
                <option value="JST">JST (TRC20)</option>
            </select>
        </label>
        <button type="submit">Start Payment Session</button>
    </form>
</body>
</html>

Payment Session Status Page

Create resources/views/payment-session.blade.php:

<!DOCTYPE html>
<html>
<head>
    <title>Payment Session</title>
</head>
<body>
    <h1>Payment Session</h1>
    <p>Send {{ $paymentSession->amount }} {{ $paymentSession->currency }} to:</p>
    <p><strong>{{ $paymentSession->wallet->address }}</strong></p>
    <p>Status: {{ $paymentSession->status }}</p>
    <p>Received: {{ $paymentSession->received_amount }} {{ $paymentSession->currency }}</p>
</body>
</html>

Step 6: Testing Your Implementation

Start the Development Server

php artisan serve

Test the Payment Flow

  1. Visit /payment and submit a payment request.
  2. Copy the generated wallet address.
  3. If using testnet, send a test transaction to that address.
  4. The webhook should automatically update the payment session status upon confirmation.

Frequently Asked Questions

What is a webhook in cryptocurrency payments?

A webhook is an HTTP callback that sends real-time notifications from the blockchain to your application when a transaction occurs. This allows your system to automatically update payment statuses without manual checks.

Can I use this for other cryptocurrencies besides Tron?

Yes. The general structure works for any blockchain that provides a similar API. You would need to adjust the API endpoints and parameters for networks like Ethereum or Bitcoin.

How do I handle transaction fees?

Transaction fees are usually deducted from the sent amount. Your application should account for this by allowing a small variance between the expected and received amounts, as shown in the tutorial.

Is it safe to store private keys in the database?

For production use, consider encrypting private keys before storage. Alternatively, use a service that manages private keys for you to enhance security.

What happens if a payment is underpaid or overpaid?

The example code includes a tolerance check (10%). Payments outside this range are marked as 'underpaid' or 'overpaid'. You can then decide to refund, request additional payment, or handle case-by-case.

How can I make the status page update automatically?

For a production application, implement frontend polling or WebSocket connections to periodically check the payment status without requiring page refreshes.


Integrating cryptocurrency payments into your Laravel application is a powerful way to accept global payments efficiently. By leveraging a blockchain API, you automate the most complex parts of the process and provide a seamless experience for your users.

👉 Discover advanced payment integration strategies