Subscriptions
This page describes Áskell’s legacy subscription flow, where a subscription is created from a PlanVariant and stored as a legacy Subscription model. For the new approach built on catalogs, bundles, and subscription contracts, see Subscription Contracts V2.
All calls to the subscription API can be tried out in our Swagger documentation, which you can find here.
Authentication
Like the rest of Áskell’s legacy API, these endpoints require a secret API key or legacy token authentication.
Authorization: Api-Key your-secret-api-key
Overview of the main endpoints
Endpoint |
Description |
|---|---|
|
Retrieves a list of legacy subscriptions. |
|
Creates a legacy subscription from nested data. |
|
Retrieves a single legacy subscription. |
|
Updates a limited set of fields on a subscription. |
|
Cancels an active subscription. |
|
Activates a subscription that is not active. |
|
Overrides the expiry of the last billing log. |
|
Runs billing if the subscription is past its |
|
Retrieves the subscriptions of a given customer. |
|
Creates a subscription for a given customer. |
|
Creates or updates a customer and creates multiple subscriptions at once. |
How the legacy flow works
A legacy subscription is based on a PlanVariant. The PlanVariant defines, among other things, the price, recurrence interval, currency, and optionally a payment processor. The amount can then be overridden on the subscription itself with amount or discount.
When a new legacy subscription is created, one of the following happens:
If a trial period is offered, a trial billing log is created and the subscription is activated without a charge.
If there is no trial period, a renewal billing log is created and the first charge is attempted immediately, unless the first billing date has been set in the future.
If the amount is 0 ISK or a free product applies, the subscription can become active without a card being charged.
List subscriptions
GET /api/subscriptions/ returns the legacy subscriptions that belong to your account.
Supported options include:
search on
referencefiltering on
referencetype=lightfor a shorter responseordering by
active_untilandstart_date
Example:
curl "https://askell.is/api/subscriptions/?type=light&ordering=-start_date" \
-H "Authorization: Api-Key your-secret-api-key"
Note
ordering and active_until apply only to this legacy flow. V2 contracts have neither active_from nor active_until, and their list does not support ordering. See Validity and cancellation in Subscription Contracts V2.
light responses include, among other things:
idplancustomer_referencestart_dateactive_untillast_billing_logamountcancelledcancel_datehas_payment_planpayment_plan_info
Retrieve a single subscription
GET /api/subscriptions/{id}/ returns a more detailed response, including billing_logs, delivery_address, and nested customer and plan data.
Direct creation with /api/subscriptions/
POST /api/subscriptions/ uses SubscriptionSerializer and expects nested plan and customer data. This endpoint is therefore usually less convenient for simple integrations than the customer-scoped create endpoint.
In practice, most integrations use either:
POST /api/customers/{reference}/subscriptions/add/for a single subscriptionPOST /api/subscriptions/multi/for multiple subscriptions at once
Create a subscription for a customer
The most common legacy creation flow is:
POST /api/customers/{reference}/subscriptions/add/
The request body can include, among other things:
Field |
Description |
|---|---|
|
ID of the |
|
Reference for the subscription. |
|
Free-text description. |
|
Optional first billing date or end of the trial period. |
|
Optional amount override. |
|
Optional discount, 0-100. |
|
Optional delivery address. |
If payment is required, the customer must already have a valid, verified payment method. If the subscription price is above 0 and there is no payment method, an error is returned.
Example:
import requests
API_KEY = 'your api key here'
headers = {
"Authorization": f"Api-Key {API_KEY}",
}
data = {
"plan": 12,
"reference": "sub-2026-0001",
"description": "Mánaðaráskrift",
"discount": "10",
}
response = requests.post(
"https://askell.is/api/customers/customer-123/subscriptions/add/",
data=data,
headers=headers,
)
Create multiple subscriptions at once
POST /api/subscriptions/multi/ updates or creates a customer and then creates more than one subscription in the same call.
This endpoint usually takes three main parts in the request body:
customerpayment_methodsubscriptions
customer contains the customer data and can also include a delivery address. payment_method can be:
{"invoice": true}a temporary
tokenfrom a temporary payment methodraw card data in older integrations
an empty object if all subscriptions are 0 ISK
Each entry in subscriptions can contain:
planreferencedescriptionamountdiscountstart_date
Example:
{
"customer": {
"customer_reference": "customer-123",
"first_name": "Jón",
"last_name": "Jónsson",
"email": "jon@example.com"
},
"payment_method": {
"token": "temporary-payment-token"
},
"subscriptions": [
{
"plan": 12,
"reference": "sub-magazine",
"description": "Tímarit"
},
{
"plan": 13,
"reference": "sub-donation",
"amount": "500"
}
]
}
Update a subscription
PATCH /api/subscriptions/{id}/ does not allow arbitrary changes to every field, but mainly supports these overrides:
planamountmetaand other serializer fields that pass validation
If plan is changed on an active subscription and the new plan has reached its subscription cap (subscription limit), an error is returned.
Cancel, activate, and change the expiry date
Legacy subscriptions support the following management calls:
Endpoint |
Description |
|---|---|
|
Cancels a subscription that is in an active state. |
|
Reactivates a subscription if it has not expired. |
|
Sets a new expiry on the last billing log. |
|
Runs billing if |
set_expiry takes the field expires and supports both:
YYYY-MM-DDYYYY-MM-DDTHH:MM:SS
On a subscription that has been migrated to a V2 contract, all of these calls reject the request, see Subscription contract accounts and migrated subscriptions.
Subscription contract accounts and migrated subscriptions
When the account’s subscription model is contracts (Subscription contracts only in the dashboard), the legacy endpoints no longer create new legacy subscriptions. The following calls then return a 400 error with code legacy_subscriptions_disabled, before a customer is created or updated and before anything is charged:
POST /api/subscriptions/POST /api/subscriptions/multi/POST /api/customers/{reference}/subscriptions/add/POST /api/checkouts/when the request includesplan. A checkout withoutplan, that is withpayment_processorandcurrencyto register a card or take a one-off amount, still works.
Payment pages that sell legacy plans reject purchases in the same way, with code legacy_subscriptions_disabled, before a card is verified or charged. The subscribe button (/subscribe-button/{plan_id}/) also rejects purchases before a customer is created or anything is charged, but it responds with an error page (400) for the buyer rather than a JSON response with code. See Payment pages.
Accounts with the subscription model legacy or dual create legacy subscriptions as before. On a contracts account, new subscriptions are created with POST /api/v2/subscription-contracts/, see Subscription Contracts V2.
{
"error": "This account uses subscription contracts and no longer creates legacy subscriptions. Use POST /api/v2/subscription-contracts/ instead.",
"code": "legacy_subscriptions_disabled",
"v2_endpoint": "/api/v2/subscription-contracts/"
}
POST /api/customers/{reference}/subscriptions/add/ also returns "status": "error", like the other errors from that endpoint.
Once a legacy subscription has been migrated to a V2 contract, the contract handles its billing. The subscription’s responses then have billing_managed_by set to subscription_contract, and migrated_to_contract_id points to the contract. On such a subscription, the following calls return a 400 error with code subscription_managed_by_contract and change nothing, whatever the account’s subscription model:
POST /api/subscriptions/{id}/cancel/, regardless of the legacy subscription’s statePOST /api/subscriptions/{id}/activate/, regardless of the legacy subscription’s statePOST /api/subscriptions/{id}/execute_billing/PATCH /api/subscriptions/{id}/andPUT /api/subscriptions/{id}/POST /api/subscriptions/{id}/set_expiry/
GET calls keep working. If the migration is reverted, billing_managed_by goes back to legacy_subscription and the calls work as before.
{
"error": "This subscription's billing is managed by subscription contract 123. Cancel it with POST /api/v2/subscription-contracts/123/cancel/ instead.",
"code": "subscription_managed_by_contract",
"migrated_to_contract_id": 123,
"v2_endpoint": "/api/v2/subscription-contracts/123/cancel/"
}
Field |
Description |
|---|---|
|
Description of the error, in English. |
|
|
|
ID of the V2 contract that handles the billing. Only present with |
|
The V2 endpoint to use instead: |
Payment plans
Responses from the legacy flow can include payment plan information if the subscription has an active payment plan:
has_payment_planpayment_plan_info
payment_plan_info can include, among other things:
total_installmentscurrent_installmentremaining_installmentsnext_installment_dateprogress_percentagestatusbilling_period_startbilling_period_end
Common errors
Error |
Description |
|---|---|
|
The |
|
A new subscription would exceed the configured subscription cap. |
|
A paid subscription was requested without a valid payment method. |
|
The discount is outside the allowed range. |
|
An attempt was made to cancel a subscription from a state that does not allow it. |
|
An attempt was made to activate an expired subscription. |
|
The account uses subscription contracts ( |
|
The subscription has been migrated to a V2 contract ( |
A note on the new model
The legacy subscription endpoints continue to work for existing integrations on accounts with the subscription model legacy or dual. On an account that uses subscription contracts only, they refuse to create new legacy subscriptions, see Subscription contract accounts and migrated subscriptions. For new integrations that need a catalog, bundles, add-ons, price versions, payment processor selection, and billing run retries, Subscription Contracts V2 is recommended.