Skip to content

Subscriptions ​

Subscriptions bill something that recurs – a pass, a plan, a server by the hour. They work like orders: create a draft, let the user confirm it, read it back.

Endpoints ​

MethodPath
GET/api/v1/subscriptionsthe user's subscriptions, newest first
POST/api/v1/subscriptionscreate a subscription
GET/api/v1/subscriptions/{id}one subscription
PUT/api/v1/subscriptions/{id}change it before checkout, afterwards only the description (trusted apps)
PUT/api/v1/subscriptions/{id}/checkoutstart it (trusted apps; third-party apps let the user confirm)
PUT/api/v1/subscriptions/{id}/pausepause: runs until the paid period ends, then expires
PUT/api/v1/subscriptions/{id}/resumeresume a paused or expired subscription
PUT/api/v1/subscriptions/{id}/revokecancel; {"refund": true} credits usage not yet charged

User token; scopes subscriptions (or subscriptions:read to read). Third-party apps can only pause, resume or revoke subscriptions they created. Trusted apps can manage subscriptions without the user's token: see App subscriptions.

Creating a subscription ​

shell
curl -X POST https://id.anikeen.com/api/v1/subscriptions \
  -H 'Authorization: Bearer USER_TOKEN' \
  -H 'Accept: application/json' -H 'Content-Type: application/json' \
  -d '{"name": "Pixel Stream Pass", "description": "All streams, every month", "unit": "month", "price": 6.714286}'
php
$subscription = $user->subscriptions()->create([
    'name' => 'Pixel Stream Pass',
    'description' => 'All streams, every month',
    'unit' => 'month',
    'price' => 6.714286,           // net per unit, 7.99 with 19 % VAT
]);

return redirect()->away($subscription->confirmationUrl(route('pass.return')));
// later: https://shop.example.com/pass/return?status=completed&subscription=01J…

Fields ​

Field
namerequired
descriptionoptional; shown on the user's bills
unitrequired: hour, day, week, month or year
pricerequired: net per unit, up to 6 decimals
groupyour app's group, e.g. a team ID
payloadyour own data (an object)
ends_atoptional end date
monthly_caphour and day units only: net, at most this per calendar month (not below price)
trial_days / trial_ends_at, trial_once, trial_payment_methoda free trial
discounta discount per billed period
withdrawal_waiver_requiredask for the early start

Subscriptions of third-party apps are drafts with a confirmation_url. The user confirms on Anikeen ID (a payment method is required, unless the trial allows none) and returns to return_url?status=completed|cancelled&subscription=<id>. Read the subscription afterwards:

php
$subscription = $user->subscriptions()->find($id);

if ($subscription->isActive()) {
    // grant access
}

Billing ​

Subscriptions are billed in arrears: each started period is added to the user's open monthly bill of your app and group, which is charged on the 1st of the following month. With a monthly_cap, an hourly or daily subscription costs at most the cap per calendar month – the units beyond it are listed at price 0.

expected_monthly_price on a subscription is a gross estimate for a month (hour × 720, day × 30, week × 30/7, year ÷ 12; with a monthly cap at most the cap).

Status ​

status (in the SDK status(), constants on Anikeen\Id\Enums\SubscriptionStatus):

statusMeaningActive
draftCreated, not confirmed by the user yetno
trialRunning, in its trial periodyes
activeRunning and billedyes
pausedRuns until the paid period ends, then expires (resume to continue)yes
cancellingRuns until a scheduled cancellation takes effectyes
expiredPaused and ran out; resume starts a new periodno
cancelledCancelled for goodno

The SDK has a shortcut for each: isActive(), isDraft(), isTrial(), isPaused(), isCancelling(), isExpired(), isCancelled().

A subscription also carries cancels_at (when a scheduled cancellation takes effect), trial_ends_at, discount, cancellation_reason (why the billing cancelled it, e.g. trial_ended_without_payment_method) and checkout_session_id (the checkout session it waits in, if any).

Pause, resume, cancel ​

php
$subscription->pause();          // expires when the paid period ends
$subscription->resume();         // an expired subscription starts a new, billed period
$subscription->revoke(refund: false);

Resuming a subscription after its paid period ran out starts a new period; the paused time isn't billed.

Webhooks ​

Follow your subscriptions through subscription.created, subscription.activated, subscription.paused, subscription.resumed, subscription.cancelled, subscription.expired and more; see the event reference.

Anikeen ID developer documentation