Integrate Authorizenet Payment Gateway In Laravel 12

image
image
image
image
image
image
image
image
Integrate Authorize.net Payment Gateway In Laravel 12

Integrate Authorize.net Payment Gateway In Laravel 12

Accepting payments on your Laravel application can be overwhelming when you're dealing with third-party gateways. Most tutorials push you toward installing packages—but what if you want full control with no extra baggage?

In this guide, I’ll walk you through integrating the Authorize.Net payment gateway in Laravel 12 without using any package, focusing on test mode to keep things safe for development. You’ll learn how to:

  1. Build a Bootstrap-powered payment form
  2. Send transactions directly to Authorize.Net
  3. Validate payment responses
  4. Securely verify webhooks from Authorize.Net


Let’s dive right in.

🧠 Why No Package?

Laravel has great community packages for payments, but they often come with extra layers of abstraction. When working with a gateway like Authorize.Net that has a detailed and well-documented API, doing it "barehanded" gives you:

  1. Full control of request structure
  2. Better debugging and logging
  3. No dependency on package updates
  4. Easier compliance with specific API versions


🛠️ Prerequisites

Before you start, make sure you have the following:

  1. Laravel 12 installed
  2. An Authorize.Net sandbox account: https://developer.authorize.net/hello_world/sandbox.html
  3. Sandbox API Login ID, Transaction Key, and Signature Key


Before moving ahead, you need to create a sandbox account to test the authorize.net, create the account from here https://developer.authorize.net/hello_world/sandbox.html


when you visit the above URL you can see the form like below one, fill the form and get your login details



Then you can login into your account from this link - https://logintest.authorize.net/?cobrand=sandbox


When you logged in you have the dashboard like the below one.


Then click on the account and look for the API keys and credentials


Click on that to get you api_login_id, transaction_key and signature_key



Add them to your .env file:

API_LOGIN_ID=your_login_id
TRANSACTION_KEY=your_transaction_key
SIGNATURE_KEY=your_signature_key_in_hex


🖼️ Step 1: Create the Payment Blade View

Let’s create a simple, clean payment form using Bootstrap 5.

Create a file at resources/views/payment.blade.php:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Authorize.Net Payment</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card shadow-lg">
<div class="card-header bg-primary text-white text-center">
<h4 class="mb-0">Pay with Authorize.Net</h4>
</div>
<div class="card-body">
@if(session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if(session('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif
<form method="POST" action="{{ route('authorize.charge') }}">
@csrf
<div class="mb-3">
<label class="form-label">Card Number</label>
<input type="text" name="card_number" class="form-control" value="4111111111111111" required>
</div>
<div class="mb-3">
<label class="form-label">Expiry Date (YYYY-MM)</label>
<input type="month" name="expiry" class="form-control" value="2025-12" required>
</div>
<div class="mb-3">
<label class="form-label">CVV</label>
<input type="text" name="cvv" class="form-control" value="123" required>
</div>
<div class="mb-3">
<label class="form-label">Amount</label>
<input type="number" step="0.01" name="amount" class="form-control" value="10.00" required>
</div>
<button type="submit" class="btn btn-success w-100">Pay Now</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

This form accepts credit card details and amount, pre-filled for testing with Authorize.Net’s sandbox test card.


📦 Step 2: Create the Controller

Now, let’s write the controller that will handle the charge and webhook logic.

Run:

php artisan make:controller AuthorizeNetController

Then update it with the following code:

<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class AuthorizeNetController extends Controller
{
private $endpoint = 'https://apitest.authorize.net/xml/v1/request.api';

public function showPaymentForm()
{
return view('payment');
}

public function chargeCustomer(Request $request)
{
$request->validate([
'card_number' => 'required',
'expiry' => 'required',
'cvv' => 'required',
'amount' => 'required|numeric',
]);

$payload = [
'createTransactionRequest' => [
'merchantAuthentication' => [
'name' => env('API_LOGIN_ID'),
'transactionKey' => env('TRANSACTION_KEY'),
],
'transactionRequest' => [
'transactionType' => 'authCaptureTransaction',
'amount' => $request->amount,
'payment' => [
'creditCard' => [
'cardNumber' => $request->card_number,
'expirationDate' => $request->expiry,
'cardCode' => $request->cvv,
],
],
],
],
];

$response = Http::withHeaders([
'Content-Type' => 'application/json',
])->post($this->endpoint, $payload);

$rawBody = $response->body();
$cleanJson = preg_replace('/^\xEF\xBB\xBF/', '', $rawBody);
$data = json_decode($cleanJson, true);

if (
isset($data['transactionResponse']['responseCode']) &&
$data['transactionResponse']['responseCode'] == '1'
) {
return back()->with('success', 'Payment successful. Transaction ID: ' . $data['transactionResponse']['transId']);
}

return back()->with('error', 'Payment failed. ' . json_encode($data['transactionResponse'] ?? $data));
}

public function handleWebhook(Request $request)
{
$signatureHeader = $request->header('X-ANET-SIGNATURE');
$payload = $request->getContent();
$generated = hash_hmac('sha512', $payload, hex2bin(env('SIGNATURE_KEY')));

if ('sha512=' . $generated === $signatureHeader) {
Log::info('Webhook verified and received:', json_decode($payload, true));
return response()->json(['message' => 'Verified'], 200);
}

Log::warning('Webhook signature mismatch!');
return response()->json(['message' => 'Invalid signature'], 403);
}
}

Key Takeaways:

  1. We use Laravel’s built-in HTTP client to send JSON to Authorize.Net.
  2. No testRequest flag is added—sandbox is already handled via the test endpoint.
  3. Webhooks are validated using HMAC SHA-512.


🌐 Step 3: Define Your Routes

Add the following routes in routes/web.php:

<?php

use App\Http\Controllers\AuthorizeNetController;

Route::get('/payment', [AuthorizeNetController::class, 'showPaymentForm'])->name('authorize.form');
Route::post('/payment', [AuthorizeNetController::class, 'chargeCustomer'])->name('authorize.charge');

// Webhook route
Route::post('/authorize-webhook', [AuthorizeNetController::class, 'handleWebhook']);

Visit /payment in your browser to view the payment form.


🌐 Step 4: Testing the integration

Run the below command

php artisan route:cache
php artisan serve

after running the above URL you can open the below URL

localhost:8000/payment

When you visit this URL, you have the UI like the one below


When click on the pay now payment being received by the authorize.net and you will receive email as for the payment like the one below




🧪 Test Card Details

Use the following test card to simulate payments in Authorize.Net sandbox:

  1. Card Number: 4111 1111 1111 1111
  2. Expiration Date: Any future date
  3. CVV: Any 3 digits
  4. Amount: Any amount, like 10.00


🔒 Webhook Security

When Authorize.Net sends webhooks (like transaction status updates), you must verify the HMAC signature using your Signature Key. Laravel makes this easy by:

  1. Reading the X-ANET-SIGNATURE header
  2. Computing HMAC with the request body
  3. Comparing them securely

Pro tip: Log these payloads first in development. Webhooks may contain important data you’ll want to store later.


✅ Benefits of This Approach

  1. You understand every line of logic
  2. No third-party abstraction
  3. Easy debugging via dd() or Log::info()
  4. Readily extendable for subscriptions, refunds, etc.


👨‍💻 Final Thoughts

Integrating Authorize.Net without a package in Laravel might look a little intimidating, but it’s really just about structuring your JSON payload properly and securing your credentials. Once you get past the first successful payment, the rest becomes straightforward.

Whether you’re building a SaaS platform, eCommerce site, or a donation portal, this method gives you the confidence that your payment logic is truly yours.


💡 Need Help or Customization?

This guide is created by CodeHunger Pvt Ltd, a Laravel development agency helping businesses integrate secure payment solutions without package bloat.

  1. 🌐 www.codehunger.in
  2. 📧 hungerforcode@gmail.com
  3. 📞 +91 9470759951

🧾 Source Code on GitHub

Explore the full working example here:

🔗 https://github.com/codehunger-team/integrate-authorize.net-in-laravel-12

Happy coding—and happy charging! 🚀