Quickstart (Laravel)
This walk-through takes a Laravel 12+ app from zero to a signed-in user and a first paid order, using the PHP SDK anikeen/id. Without Laravel, follow the same steps with the OAuth flow and the orders API.
1. Install the SDK
shell
composer require anikeen/id2. Configure your credentials
Use the OAuth client of your app on staging while you develop:
ini
ANIKEEN_ID_MODE=staging
ANIKEEN_ID_KEY=your-client-id
ANIKEEN_ID_SECRET=your-client-secret
ANIKEEN_ID_CALLBACK_URL=http://localhost/auth/callback
ANIKEEN_ID_WEBHOOK_SECRET=whsec_...and add them to config/services.php:
php
'anikeen' => [
'mode' => env('ANIKEEN_ID_MODE'),
'client_id' => env('ANIKEEN_ID_KEY'),
'client_secret' => env('ANIKEEN_ID_SECRET'),
'redirect' => env('ANIKEEN_ID_CALLBACK_URL'),
'base_url' => env('ANIKEEN_ID_BASE_URL'),
'webhook_secret' => env('ANIKEEN_ID_WEBHOOK_SECRET'),
],3. Register the Socialite provider
In AppServiceProvider::boot():
php
use Illuminate\Support\Facades\Event;
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
$event->extendSocialite('anikeen', \Anikeen\Id\Socialite\Provider::class);
});4. Prepare the user model
php
Schema::table('users', function (Blueprint $table) {
$table->string('anikeen_id')->nullable()->unique();
$table->text('anikeen_id_access_token')->nullable();
$table->text('anikeen_id_refresh_token')->nullable();
});php
use Anikeen\Id\Billable;
class User extends Authenticatable
{
use Billable;
protected $hidden = ['password', 'remember_token', 'anikeen_id_access_token', 'anikeen_id_refresh_token'];
protected function casts(): array
{
return [
'anikeen_id_access_token' => 'encrypted',
'anikeen_id_refresh_token' => 'encrypted',
];
}
}5. Sign the user in
php
use Laravel\Socialite\Facades\Socialite;
Route::get('auth/redirect', fn () => Socialite::driver('anikeen')
->scopes(['user:read', 'addresses:read', 'orders', 'subscriptions'])
->redirect());
Route::get('auth/callback', function () {
$account = Socialite::driver('anikeen')->user();
$user = User::updateOrCreate(['anikeen_id' => $account->getId()], [
'name' => $account->getName() ?: $account->getNickname(),
'email' => $account->getEmail(),
'anikeen_id_access_token' => $account->token,
'anikeen_id_refresh_token' => $account->refreshToken,
]);
Auth::login($user, remember: true);
return redirect()->intended('/');
});6. Sell something
Create the order as a draft and send the user to Anikeen ID to confirm and pay:
php
Route::post('checkout', function () {
$user = auth()->user();
$order = $user->orders()->create([
'billing_address_id' => $user->getUserData()->billing_address_id,
'items' => [
['type' => 'digital', 'name' => 'Sticker pack', 'unit' => 'piece', 'units' => 1, 'gross_price' => '9.99'],
],
]);
return redirect()->away($order->confirmationUrl(route('checkout.return')));
});
Route::get('checkout/return', function (Request $request) {
// never trust the query string: read the order through the API
$order = auth()->user()->orders()->find($request->query('order'));
return view('checkout.done', ['paid' => $order->status === 'completed']);
})->name('checkout.return');7. Fulfil on the webhook
php
use Anikeen\Id\Exceptions\SignatureVerificationException;
use Anikeen\Id\Webhooks\EventType;
use Anikeen\Id\Webhooks\Webhook;
Route::post('webhooks/anikeen', function (Request $request) {
try {
$event = Webhook::constructEvent(
$request->getContent(),
$request->header('Anikeen-Signature'),
config('services.anikeen.webhook_secret'),
);
} catch (SignatureVerificationException) {
abort(400);
}
if ($event['type'] === EventType::ORDER_COMPLETED) {
Shop::fulfil($event['data']['object']['id']);
}
return response()->noContent();
});Exclude the route from CSRF protection in bootstrap/app.php:
php
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: ['webhooks/*']);
})Pay on staging with Stripe's test card 4242 4242 4242 4242.