Files
id/README.md
T
Maurice PreußandClaude Opus 5.5 9613d31a8d Bring the package up to date with the Anikeen ID API
Fixed (called endpoints that don't exist):
- charge(): POST v1/billing/charge (Stripe options aren't passed through anymore)
- Invoice::getInvoiceTemporaryUrl(): GET instead of a non-existent PUT
- OrderItems::create(): POST v1/orders/{order}/items
- createUser() / isEmailExisting(): admin endpoints with the app token
- sshKeysByUserId(): app endpoint; no longer returns the first user's keys for every user
- createOrderPreview(): country_iso goes into billing_address as the API expects
- public endpoints (products, order preview) work without a token
- SshKeys::find() results can be deleted

Added:
- Billable: sshKeys() (create, update, delete), billingOverview(), PaymentMethod::delete()
- AnikeenId: products(), boxes(), shipping labels (list, show, pdf, issue, ship, price list),
  createOrderForUser(), createTransactionForUser(), findOrCreateSocialiteUser()

Requirements: PHP 8.2+, Laravel 11-13 (Laravel 10 and PHP 8.1 are end of life).
Docs generator handles union types; README regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 17:18:05 +01:00

12 KiB

Anikeen ID

Latest Stable Version Total Downloads License

PHP Anikeen ID API Client for Laravel 11+

Table of contents

  1. Installation
  2. Configuration
  3. General
  4. Examples
  5. Documentation
  6. Development

Installation

composer require anikeen/id

Configuration

Add environmental variables to your .env file:

ANIKEEN_ID_KEY=
ANIKEEN_ID_SECRET=
ANIKEEN_ID_CALLBACK_URL=http://localhost/auth/callback

To switch from production to staging use following variable:

ANIKEEN_ID_MODE=staging

You will need to add an entry to the services configuration file so that after config files are cached for usage in production environment (Laravel command artisan config:cache) all config is still available.

Add to config/services.php file:

'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'),
],

Event Listener

In Laravel 11, the default EventServiceProvider provider was removed. Instead, add the listener using the listen method on the Event facade, in your AppServiceProvider boot method:

public function boot(): void
{
    Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
        $event->extendSocialite('anikeen', \Anikeen\Id\Socialite\Provider::class);
    });
}

Registering Middleware

Append it to the global middleware stack in your application's bootstrap/app.php file:

->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        \Anikeen\Id\Http\Middleware\CreateFreshApiToken::class,
    ]);
})

Implementing Billable

To implement the Billable trait, you need to add the Billable trait to your user model.

use Anikeen\Id\Billable;

class User extends Authenticatable
{
    use Billable;

    // Your model code...
}

then, you can use the Billable trait methods in your user model.

App subscriptions (trusted apps, no user token)

subscriptions() acts with the user's own access token and stops working when the user's login expired. Trusted apps can manage a user's subscriptions with the app's own token (client credentials, scope subscriptions:client) instead:

$subscriptions = $team->owner->appSubscriptions(); // nothing is requested yet

$subscription = $subscriptions->create([
    'group' => $team->id,
    'name' => 'Cloud Server S',
    'unit' => 'hour',
    'price' => 0.0137,
    'idempotency_key' => "server:{$pendingServer->id}", // retries return the same subscription
]);

$subscription->checkout();             // bill the first period
$subscription->pause();                // expires when the paid period ends
$subscription->resume();               // expired subscriptions start a new period
$subscription->revoke(refund: false);  // cancel

$subscriptions->find($id);             // null if unknown or not this user's
$subscriptions->all(['group' => $team->id, 'active' => true]);

The user's Anikeen ID is read from the billable's anikeen_id attribute (AnikeenId::useUserIdField('…') to change it). The app must be trusted by Anikeen ID; it sees the subscriptions it created (plus those of clients delegated to it).

Failures throw Anikeen\Id\Exceptions\ApiException with status (0 = not reachable), a stable error code (already_active, already_cancelled, not_active, already_paused, already_resumed, billing_address_missing, not_changeable, subscription_not_found, idempotency_key_conflict) and isNotFound(), isConflict(), isTemporary():

try {
    $subscription->revoke();
} catch (ApiException $e) {
    if ($e->isNotFound() || $e->error === 'already_cancelled') {
        // already gone
    } elseif ($e->isTemporary()) {
        // retry later
    } else {
        throw $e;
    }
}

Change the default access token / refresh token field name

If you access / refresh token fields differs from the default anikeen_id_access_token / anikeen_id_refresh_token, you can specify the field name in the AppServiceProvider boot method:

use Anikeen\Id\AnikeenId;

public function boot(): void
{
    AnikeenId::useAccessTokenField('anikeen_id_access_token');
    AnikeenId::useRefreshTokenField('anikeen_id_refresh_token');
}

Implementing Auth

This method should typically be called in the boot method of your AppServiceProvider class:

use Anikeen\Id\AnikeenId;
use Anikeen\Id\Providers\AnikeenIdUserProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

public function boot(): void
{
    Auth::provider('anikeen', function ($app, array $config) {
        return new AnikeenIdUserProvider(
            $app->make(AnikeenId::class),
            $app->make(Request::class),
            $config['model'],
            $config['fields'] ?? [],
        );
    });
}

reference the guard in the guards configuration of your auth.php configuration file:

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'api' => [
        'driver' => 'anikeen',
        'provider' => 'anikeen',
    ],
],

reference the provider in the providers configuration of your auth.php configuration file:

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],

    'anikeen' => [
        'driver' => 'anikeen',
        'model' => App\Models\User::class,
        'fields' => ['first_name', 'last_name', 'email'],
    ],
],

General

Setters and Getters

$anikeenId = new Anikeen\Id\AnikeenId();

$anikeenId->setClientId('abc123');
$anikeenId->setClientSecret('abc456');
$anikeenId->setToken('abcdef123456');

$anikeenId = $anikeenId->withClientId('abc123');
$anikeenId = $anikeenId->withClientSecret('abc123');
$anikeenId = $anikeenId->withToken('abcdef123456');

Error handling for an unsuccessful query:

$result = $anikeenId->sshKeysByUserId('someInvalidId');

// Check, if the query was successfully
if (!$result->success()) {
    die('Ooops: ' . $result->error());
}

Shift result to get single key data:

$result = $anikeenId->sshKeysByUserId('someValidId');

$sshKey = $result->shift();

echo $sshKey->name;

Examples

Get User SSH Key

$anikeenId = new Anikeen\IdAnikeenId();

$anikeenId->setClientId('abc123');

// Get SSH Key by User ID
$result = $anikeenId->sshKeysByUserId('someValidId');

// Check, if the query was successfully
if (!$result->success()) {
    die('Ooops: ' . $result->error());
}

// Shift result to get single key data
$sshKey = $result->shift();

echo $sshKey->name;

Create Order Preview

$anikeenId = new \Anikeen\Id\AnikeenId();

// Create new Order Preview
$result = $anikeenId->createOrderPreview([
    'country_iso' => 'de',
    'items' => [
        [
            'type' => 'physical',
            'name' => 'Test',
            'price' => 2.99,
            'unit' => 'onetime',
            'units' => 1,
        ]
    ]
])->shift();

echo $preview->gross_total;

OAuth Tokens

$anikeenId = new Anikeen\Id\AnikeenId();

$anikeenId->setClientId('abc123');
$anikeenId->setToken('abcdef123456');

$result = $anikeenId->getAuthedUser();

$user = $userResult->shift();
$anikeenId->setToken('uvwxyz456789');

$result = $anikeenId->getAuthedUser();
$result = $anikeenId->withToken('uvwxyz456789')->getAuthedUser();

Facade

use Anikeen\Id\Facades\AnikeenId;

AnikeenId::withClientId('abc123')->withToken('abcdef123456')->getAuthedUser();

Documentation

AnikeenId

Oauth

public function retrievingToken(string $grantType, array $attributes): Result

ManagesPricing

public function createOrderPreview(array $attributes = []): Result

ManagesProducts

public function products(): Result
public function boxes(): Result

ManagesShippingLabels

public function shippingLabels(array $parameters = []): Result
public function shippingLabel(string $id): Result
public function shippingLabelPdf(string $id): ?string
public function issueShippingLabel(array $attributes): Result
public function shipShippingLabel(array $hex): Result
public function shippingPriceList(): Result

ManagesUserBilling

public function createOrderForUser(string $userId, array $attributes): Result
public function createTransactionForUser(string $userId, array $attributes): Result

ManagesSocialiteUsers

public function socialiteUsers(): SocialiteUsers

ManagesSshKeys

public function sshKeysByUserId(string $userId): SshKeys

ManagesUsers

public function getAuthedUser(): Result
public function createUser(array $attributes): Result
public function findOrCreateSocialiteUser(string $provider, string $providerId, ?string $email = null, ?string $name = null): Result
public function refreshToken(string $storedRefreshToken, string $scope = ''): Result
public function isEmailExisting(string $email): Result
public function setParent(mixed $parent): self
public function getParent()

Billable

ManagesAddresses

public function addresses(): Addresses
public function hasDefaultBillingAddress(): bool
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesBalance

public function balance(): float
public function charges(): float
public function billingOverview(): object
public function charge(string|float $amount, string $paymentMethodId, array $options = []): Transaction
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesCountries

public function countries(): Countries
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesInvoices

public function invoices(array $parameters = []): Invoices
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesOrders

public function orders(array $parameters = []): Orders
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesPaymentMethods

public function paymentMethods(): PaymentMethods
public function hasPaymentMethod(): ?PaymentMethod
public function defaultPaymentMethod(): ?PaymentMethod
public function hasDefaultPaymentMethod(): bool
public function setDefaultPaymentMethod(string $id): PaymentMethod
public function billingPortalUrl(?string $returnUrl = null, array $options = []): string
public function createSetupIntent(array $options = []): Result
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesProfile

public function profilePortalUrl(?string $returnUrl = null, array $options = []): string
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesSubscriptions

public function subscriptions(): Subscriptions
public function appSubscriptions(): AppSubscriptions
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesTaxation

public function vatRate(): float
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesTransactions

public function transactions(): Transactions
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

ManagesUserSshKeys

public function sshKeys(): SshKeys
public function setBillable(Billable|Model $billable): self
public function getBillable(): Billable

OAuth Scopes Enums

Development

Run Tests

composer test
BASE_URL=xxxx CLIENT_ID=xxxx CLIENT_KEY=yyyy CLIENT_ACCESS_TOKEN=zzzz composer test

Generate Documentation

composer docs