This section is designed for developers who are using Laravel, a popular PHP framework, to integrate webhook notifications from Ottu. We aim to provide clear and practical examples to help you effectively set up and handle webhook events within your Laravel applications.
In this section, we focus on setting up the necessary database models and migrations required to handle and store webhook notifications, both and , and related data in a Laravel application. Our primary goal is to capture data associated with both the webhook notifications and the efficiently.
We need two models: and .
The Checkout model:
It will store the details of the checkout process, including the which uniquely identifies each payment transaction.
The Webhook model:
It will be used to capture and store the data from webhook notifications.
The represents the data structure for storing information received from the . Here is how you can set up this model and its corresponding migration:
Model Definition:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Checkout extends Model
{
use HasFactory;
protected $primaryKey = 'session_id';
public $incrementing = false;
protected $keyType = 'string';
protected $fillable = [
'session_id', 'type', 'payment_type', 'amount', 'currency_code',
'state', 'customer_id', 'token', 'agreement', 'extra_params'
];
protected $casts = [
'agreement' => 'array',
'extra_params' => 'array',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
public function webhooks()
{
return $this->hasMany(Webhook::class);
}
}
Migration for Checkout Table:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCheckoutsTable extends Migration
{
public function up()
{
Schema::create('checkouts', function (Blueprint $table) {
$table->string('session_id', 100)->primary();
$table->string('type', 250);
$table->string('payment_type', 250);
$table->string('amount', 20);
$table->string('currency_code', 10);
$table->string('state', 250);
$table->string('customer_id', 250)->nullable();
$table->string('token', 250)->nullable();
$table->json('agreement')->nullable();
$table->json('extra_params')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('checkouts');
}
}
Model Definition:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Webhook extends Model
{
use HasFactory;
protected $fillable = [
'session_id',
'checkout_id',
'payload'
];
protected $casts = [
'payload' => 'array',
'timestamp' => 'datetime',
];
public function checkout()
{
return $this->belongsTo(Checkout::class);
}
}
Migration for Webhooks Table:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateWebhooksTable extends Migration
{
public function up()
{
Schema::create('webhooks', function (Blueprint $table) {
$table->id();
$table->string('session_id', 250);
$table->foreignId('checkout_id')
->nullable()
->constrained('checkouts')
->onDelete('cascade');
$table->json('payload')->nullable();
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('webhooks');
}
}
A Controller will need to be created. Below can be generated using the artisan command:
php artisan make:controller WebhookController
Below is how the WebhookController could be structured, translating the functionality from the Django view:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Webhook;
use Illuminate\Support\Facades\Log;
class WebhookController extends Controller
{
public function handle(Request $request)
{
Log::info('Webhook received: ' . $request->getContent());
if (!$this->verifySignature($request)) {
return response()->json(['detail' => 'Unable to verify signature'], 401);
}
try {
$processedData = $this->processData($request);
$this->saveData($processedData);
return response()->json(['detail' => 'Success'], 200);
} catch (\Exception $e) {
Log::error('Failed to process webhook: ' . $e->getMessage());
return response()->json(['detail' => 'Failed to process webhook'], 400);
}
}
protected function verifySignature(Request $request)
{
// Assume `verify_signature` is a helper function you've set up as per the signing mechanism section:
// https://docs.ottu.com/developer/webhooks/signing-mechanism#php
return verify_signature($request->getContent(), $request->header('Signature'));
}
protected function processData(Request $request)
{
// Extract data from $request and perform any necessary transformations to process the data sent by Ottu
return json_decode($request->getContent(), true);
}
protected function saveData(array $data)
{
// Use the data array to create or update your models
Webhook::create([
'session_id' => $data['session_id'],
'checkout_id' => $data['checkout_id'] ?? null,
'payload' => $data
]);
}
}
Key Points:
Signature Verification:
Integrating with Laravel Routes:
Define a route in Laravel that directs to this controller method by adding the following line to your routes file (typically located in routes/web.php):
Route::post('/webhook', [WebhookController::class, 'handle']);
Logging:
Log all incoming data from Ottu before processing. This is crucial for maintaining detailed records useful for troubleshooting and auditing purposes.
Response Status Codes:
Carefully manage the response status codes sent back to Ottu to ensure clear communication about the success or failure of the webhook handling.
Conclusion:
Response Status Codes: Exercise meticulous care in managing the response status codes returned to Ottu. This is critical for ensuring transparent communication regarding the success or failure of the webhook handling.
These enhancements and best practices will optimize your webhook integration and ensure effective communication and compliance within the Laravel framework.
The is used to store each webhook notification, including the payload and the timestamp when it was received.
Implement the verify_signature function to confirm the authenticity of incoming webhooks. This involves comparing a signature calculated from the request payload with the signature provided in the webhook headers. For detailed instructions on how to perform this verification, refer to our section.
The example code provided above offers a foundational framework for developing your own webhook receiver in a Laravel environment. To enhance integration, it's important to adhere to the outlined above and incorporate the following best practices:
Endpoint Requirements: Gain a thorough understanding of all endpoint requirements to ensure complete compliance with Ottu's operational standards. Detailed information on these requirements is available on our page.