Drop NexiSim into your Laravel app
Everything below is copy-paste ready: env vars, a config file, routes, a controller, and four named Blade views — including a working test page. Your API key stays on the server the whole time; the browser never sees it.
Requirements
Nothing extra to install — Laravel's built-in HTTP client (Guzzle under the hood) is all you need.
- ✓ Laravel 9, 10, or 11
- ✓
illuminate/http— ships with Laravel by default - ✓ A NexiSim account with an API key (see "Where to buy" below)
Environment variables
Add these two lines to your .env file.
NEXISIM_API_KEY=your_api_key_here NEXISIM_BASE_URL=https://www.nexisim.co.ke/api/v2
Config file
Create this file so the key and base URL are available anywhere via config('nexisim...').
<?php
return [
'api_key' => env('NEXISIM_API_KEY'),
'base_url' => env('NEXISIM_BASE_URL', 'https://www.nexisim.co.ke/api/v2'),
];
Routes
Add this group to your existing routes file. It covers the dashboard page, the tester page, and the JSON endpoints the tester calls.
use App\Http\Controllers\NexisimController;
Route::prefix('nexisim')->name('nexisim.')->group(function () {
Route::get('/', [NexisimController::class, 'index'])->name('index');
Route::get('/tester', [NexisimController::class, 'tester'])->name('tester');
Route::get('/countries/{service}', [NexisimController::class, 'countries'])->name('countries');
Route::post('/buy', [NexisimController::class, 'buy'])->name('buy');
Route::get('/check-sms/{id}', [NexisimController::class, 'checkSms'])->name('check-sms');
Route::get('/orders', [NexisimController::class, 'orders'])->name('orders');
});
/nexisim (dashboard), /nexisim/tester (test page), plus the JSON routes the tester calls under the hood.
Controller
One controller handles every endpoint. Each method returns a Blade view normally, or JSON when the request asks for it (that's what powers the tester page without duplicating logic).
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
class NexisimController extends Controller
{
protected function client()
{
return Http::withToken(config('nexisim.api_key'))
->baseUrl(config('nexisim.base_url'));
}
public function index(Request $request)
{
$services = $this->client()->get('/services')->json();
if ($request->wantsJson()) {
return response()->json($services);
}
return view('nexisim.index', [
'services' => $services,
]);
}
public function countries(string $service)
{
return response()->json(
$this->client()->get("/countries/{$service}")->json()
);
}
public function buy(Request $request)
{
$data = $request->validate([
'service_id' => 'required',
'country_id' => 'required',
]);
$result = $this->client()->post('/buy', $data)->json();
if ($request->wantsJson()) {
return response()->json($result);
}
return view('nexisim.buy', [
'result' => $result,
]);
}
public function checkSms(string $id)
{
return response()->json(
$this->client()->get("/check-sms/{$id}")->json()
);
}
public function orders(Request $request)
{
$orders = $this->client()->get('/orders')->json();
if ($request->wantsJson()) {
return response()->json($orders);
}
return view('nexisim.orders', [
'orders' => $orders,
]);
}
public function tester()
{
return view('nexisim.tester');
}
}
Dashboard view
Lists every service and lets someone buy a number for it right from the page.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>NexiSim — Services</title>
<style>
body { font-family: sans-serif; background:#0b0e14; color:#e4e8f1; padding:40px; }
.card { background:#141a24; border:1px solid #232b3a; border-radius:12px; padding:18px; margin-bottom:12px; }
.card h3 { margin:0 0 8px; }
form { display:flex; gap:8px; margin-top:10px; }
input { flex:1; padding:8px; border-radius:6px; border:1px solid #232b3a; background:#0b0e14; color:#fff; }
button { padding:8px 16px; border:none; border-radius:6px; background:#22c55e; color:#031a0b; font-weight:700; cursor:pointer; }
</style>
</head>
<body>
<h1>Available services</h1>
@foreach ($services as $service)
<div class="card">
<h3>{{ $service['name'] }}</h3>
<span>Service ID: {{ $service['id'] }}</span>
<form action="{{ route('nexisim.buy') }}" method="POST">
@csrf
<input type="hidden" name="service_id" value="{{ $service['id'] }}">
<input type="text" name="country_id" placeholder="Country ID" required>
<button type="submit">Buy number</button>
</form>
</div>
@endforeach
<p><a href="{{ route('nexisim.orders') }}" style="color:#22c55e;">View orders →</a></p>
<p><a href="{{ route('nexisim.tester') }}" style="color:#22c55e;">Open the API tester →</a></p>
</body>
</html>
Buy result view
Shows the number you just bought and polls for the OTP with a button — no extra JS framework required.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>NexiSim — Number purchased</title>
<style>
body { font-family: sans-serif; background:#0b0e14; color:#e4e8f1; padding:40px; }
.card { background:#141a24; border:1px solid #232b3a; border-radius:12px; padding:20px; max-width:420px; }
button { padding:10px 18px; border:none; border-radius:6px; background:#22c55e; color:#031a0b; font-weight:700; cursor:pointer; margin-top:14px; }
pre { background:#050810; padding:12px; border-radius:8px; overflow-x:auto; margin-top:12px; }
</style>
</head>
<body>
<div class="card">
<h1>Number purchased</h1>
@if (($result['status'] ?? null) === 'success')
<p>Phone number: <strong>{{ $result['phone_number'] }}</strong></p>
<p>Activation ID: <strong>{{ $result['activation_id'] }}</strong></p>
<p>Cost: <strong>{{ $result['cost'] }}</strong></p>
<button id="checkBtn" data-id="{{ $result['activation_id'] }}">Check for SMS</button>
<pre id="smsResult">Waiting…</pre>
@else
<p style="color:#f87171;">{{ $result['error'] ?? 'Something went wrong.' }}</p>
@endif
<p><a href="{{ route('nexisim.index') }}" style="color:#22c55e;">← Back to services</a></p>
</div>
<script>
const btn = document.getElementById('checkBtn');
if (btn) {
btn.addEventListener('click', async () => {
const id = btn.dataset.id;
const res = await fetch(`/nexisim/check-sms/${id}`, {
headers: { 'Accept': 'application/json' }
});
const data = await res.json();
document.getElementById('smsResult').textContent = JSON.stringify(data, null, 2);
});
}
</script>
</body>
</html>
Orders view
A simple table of past orders.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>NexiSim — Orders</title>
<style>
body { font-family: sans-serif; background:#0b0e14; color:#e4e8f1; padding:40px; }
table { width:100%; border-collapse:collapse; background:#141a24; border-radius:12px; overflow:hidden; }
th, td { padding:12px 16px; text-align:left; border-bottom:1px solid #232b3a; }
th { color:#8494b4; font-size:12px; text-transform:uppercase; }
</style>
</head>
<body>
<h1>Your orders</h1>
<table>
<thead>
<tr>
<th>Service</th>
<th>Country</th>
<th>Status</th>
<th>Phone number</th>
</tr>
</thead>
<tbody>
@forelse ($orders as $order)
<tr>
<td>{{ $order['service'] }}</td>
<td>{{ $order['country'] }}</td>
<td>{{ $order['status'] }}</td>
<td>{{ $order['phone_number'] }}</td>
</tr>
@empty
<tr><td colspan="4">No orders yet.</td></tr>
@endforelse
</tbody>
</table>
<p><a href="{{ route('nexisim.index') }}" style="color:#22c55e;">← Back to services</a></p>
</body>
</html>
Tester view
A self-contained test page for your own team — no API key typed into the browser, since it calls your Laravel routes, which hold the key server-side.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>NexiSim — Internal tester</title>
<style>
body { font-family: sans-serif; background:#0b0e14; color:#e4e8f1; padding:40px; max-width:640px; margin:0 auto; }
.card { background:#141a24; border:1px solid #232b3a; border-radius:12px; padding:20px; margin-bottom:16px; }
.card h3 { margin-bottom:10px; }
input { width:100%; padding:9px 12px; border-radius:6px; border:1px solid #232b3a; background:#0b0e14; color:#fff; margin-bottom:10px; font-family:monospace; }
button { padding:9px 18px; border:none; border-radius:6px; background:#22c55e; color:#031a0b; font-weight:700; cursor:pointer; }
pre { background:#050810; padding:12px; border-radius:8px; overflow-x:auto; margin-top:12px; font-size:12.5px; white-space:pre-wrap; word-break:break-word; }
</style>
</head>
<body>
<h1>NexiSim internal tester</h1>
<p style="color:#8494b4;margin-bottom:24px;">Calls your own Laravel routes, which hold the API key. Safe to share with teammates.</p>
<div class="card">
<h3>Services</h3>
<button onclick="run('GET', '/nexisim', null, 'out-services')">Fetch services</button>
<pre id="out-services">—</pre>
</div>
<div class="card">
<h3>Countries</h3>
<input id="in-service" placeholder="Service ID">
<button onclick="run('GET', '/nexisim/countries/' + val('in-service'), null, 'out-countries')">Fetch countries</button>
<pre id="out-countries">—</pre>
</div>
<div class="card">
<h3>Buy number</h3>
<input id="in-buy-service" placeholder="Service ID">
<input id="in-buy-country" placeholder="Country ID">
<button onclick="run('POST', '/nexisim/buy', { service_id: val('in-buy-service'), country_id: val('in-buy-country') }, 'out-buy')">Buy number</button>
<pre id="out-buy">—</pre>
</div>
<div class="card">
<h3>Check SMS</h3>
<input id="in-activation" placeholder="Activation ID">
<button onclick="run('GET', '/nexisim/check-sms/' + val('in-activation'), null, 'out-sms')">Check SMS</button>
<pre id="out-sms">—</pre>
</div>
<div class="card">
<h3>Orders</h3>
<button onclick="run('GET', '/nexisim/orders', null, 'out-orders')">Fetch orders</button>
<pre id="out-orders">—</pre>
</div>
<script>
function val(id) { return document.getElementById(id).value.trim(); }
async function run(method, url, body, outId) {
const out = document.getElementById(outId);
out.textContent = 'Running…';
const opts = {
method,
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content
}
};
if (body) {
opts.headers['Content-Type'] = 'application/json';
opts.body = JSON.stringify(body);
}
try {
const res = await fetch(url, opts);
const data = await res.json();
out.textContent = JSON.stringify(data, null, 2);
} catch (err) {
out.textContent = 'Error: ' + err.message;
}
}
</script>
</body>
</html>
/nexisim/tester once the routes are in place — that's this page, live in your app.
Where to buy / top up
Numbers are purchased against your NexiSim account balance — top up and grab your API key from the same place.
NexiSim Dashboard
Sign in, top up your balance, and copy your live API key — this is also where the numbers your app buys are actually paid for.
Install checklist
Do these in order and you're live.
- 1 Add the two lines to
.env - 2 Create
config/nexisim.php - 3 Create
app/Http/Controllers/NexisimController.php - 4 Create the four files in
resources/views/nexisim/ - 5 Paste the route group into
routes/web.php - 6 Run
php artisan config:clearso the new env vars load - 7 Visit
/nexisim/testerand try a request