Member subscriptions

Read the member's memberships and change the renewal preference on an existing Pricing relationship. Exact API subscription names are retained: these routes use a Pricing ID, while membership means the member's existing relationship. Selecting a new Pricing for purchase belongs to checkout.

TaskOperation
Read member memberships in the resourceList subscriptions
Turn existing renewal preference on/offChange renewal

Read memberships in this resource

GET /api/v1/user/subscriptions

Read Pricing objects with this member’s membership dates and renewal flags added. This is not a public catalog listing or a list filtered to active/unexpired records: the query selects existing member relationships joined to their Pricing and Plan.

Before you call

Establish member identity, or its Firebase identity, in a valid resource. A relationship must exist to produce an item. Public Pricing availability alone is not membership.

Request

GET with no body or request Content-Type. Requires user role/inherited permission and active/unlocked member context. Supply sample configuration.

NameLocationTypeRequirement / defaultMeaning
resourceheaderstringmember request contextPublic resource key for ordinary member-session lookup and resource-aware response. The controller requires user, not an explicit require-resource guard; provide valid resource context.
tokenheaderstringmember contextExisting Wallkit member token; user role or inherited permission.
firebase-tokenheaderstringconfigured Firebase contextExisting Firebase ID token alongside Wallkit token; see credentials.
pagequeryintegeroptional; examples pass 1Page selection; no explicit omitted-page default in the paginator call.
limitqueryintegeroptional; configured results_on_pagePage size; not the controller's fixed 10 default. No universal maximum specified.
filterqueryobject / JSON stringoptionalModel-field criteria across UserPlanRelationships, Subscriptions and Plans. Bracket/JSON transport; text substring and numeric comparisons/arrays as supported by the common filter.
order / byquerystringoptionalorder overrides by; default UserPlanRelationships.created_at.
sortquerystringoptional, DESCOrdering direction; ASC/DESC for ordinary use.

Pass limit explicitly: the paginator uses configured results_on_page (documented default: 10), while the omitted-limit response field uses the controller default 10; changed configuration can make those defaults differ.

The query is restricted to member ID and Plan resource, grouped by membership ID. Several membership records can therefore produce repeated Pricing IDs. The returned id is the Pricing ID, not the grouping membership ID. Filter errors do not have this action's explicit validity/error gate; do not assume the transaction-list error handling applies here.

Result

HTTP 200 JSON items[] plus paginator fields. Each item contains general Pricing, including its selected nested catalog fields, plus:

Additional fieldType / presenceMeaning
subscription_start_datestored timestamp string / nullableMembership creation time.
subscription_end_datestored timestamp string / nullableMembership expiration.
subscription_updated_datestored timestamp string / nullableMembership update time.
autorenewbooleanMember's current renewal preference.
is_trialbooleanMembership trial flag.
is_team_subscriptionbooleanTeam membership flag.

No timezone guarantee or content entitlement is implied. Empty items is an ordinary no-matching-record result.

Example: read Pricing 2001's relationship

The member already has a relationship to Pricing 2001; dates and flags explain its recorded state. The three requests are equivalent.

cURL

curl "${WALLKIT_API_BASE}/api/v1/user/subscriptions?page=1&limit=10" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}"

JavaScript

// Node.js 18+; built-in fetch.
async function main() {
  const url = new URL("/api/v1/user/subscriptions", process.env.WALLKIT_API_BASE);
  url.searchParams.set("page", "1");
  url.searchParams.set("limit", "10");
  const response = await fetch(url, { method: "GET", headers: {
    resource: process.env.RESOURCE_KEY, token: process.env.USER_TOKEN
  }});
  console.log(response.status, await response.json());
}
main().catch(console.error);

Python

# Python 3; standard library only.
import json
import os
from urllib.error import HTTPError
from urllib.parse import urlencode, urljoin
from urllib.request import Request, urlopen

url = urljoin(os.environ["WALLKIT_API_BASE"], "/api/v1/user/subscriptions") + "?" + urlencode({'page': '1', 'limit': '10'})
headers = {"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"]}
request = Request(url, headers=headers, method="GET")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

HTTP 200 response excerpt (catalog fields/paginator omitted):

{"items":[{"id":2001,"plan_id":1001,"title":"Monthly","subscription_start_date":"2026-09-01 10:00:00","subscription_end_date":"2026-10-01 10:00:00","subscription_updated_date":"2026-09-01 10:00:00","autorenew":true,"is_trial":false,"is_team_subscription":false}]}

Use Pricing 2001 for renewal preference requests, not an invented membership ID. Dates are recorded values, not proof that an article is currently allowed.

Consequential alternate: no matching memberships

HTTP 200 excerpt:

{"items":[]}

Show an empty account state and check selected filters/resource before offering a purchase. The result is not an authentication error or a complete cross-resource membership history.

Recovery

HTTPCode / responseCauseNext action
401auth_failed / auth_access_failMissing/invalid member or inactive/locked/suspended context.Check the existing session/resource; ask the administrator about restrictions.
200items: []No matching joined relationships in the selected member/resource/filter scope.Check scope/filters; read the catalog only if a new Pricing selection is needed.

No handler-specific resource/filter failure status is promised beyond these visible branches. Supply a valid resource and supported field criteria; do not replace missing context with an empty-account assumption.

Next task

Use renewal change for an existing relationship, or select a new Pricing through checkout. For content serving, obtain the separate access decision.

Change renewal on an existing relationship

POST /api/v1/user/subscriptions/{id}

Set the existing member/Pricing relationship's autorenew preference. This does not switch the member to another Pricing, perform an immediate charge, cancel access, refund a payment or delete the membership. The profile PUT and profile DELETE retain their distinct contracts.

Before you call

Requires active member context and user-role/inherited permission. The numeric path ID must identify an existing Pricing with a relationship for this member. Enabling renewal requires that Pricing's is_allowed_autorenew. The lookup checks member/Pricing IDs without a separate header-resource match; retain the intended member/resource/Pricing association in your integration.

The helper saves the renewal flag, invalidates membership caches and requests renewal events/conditional Campaign Monitor sync. It does not check the save boolean before the handler returns success. Read the returned state; HTTP 200 does not promise future successful renewal or event delivery. No membership deletion/payment-provider call is performed by this action itself.

Request

POST JSON object; null/omitted autorenew does not enter the update branch. Send a JSON boolean. The source's BooleanFilter treats false/empty and trimmed "false" as false, other truthy sanitized values as true; this is not strict JSON-boolean validation.

NameLocationTypeRequirementMeaning
resourceheaderstringmember request contextPublic resource key for ordinary member-session lookup and resource-aware response. The controller requires user, not an explicit require-resource guard; provide valid resource context.
tokenheaderstringmember contextExisting Wallkit member token; user role or inherited permission.
firebase-tokenheaderstringconfigured Firebase contextExisting Firebase ID token alongside Wallkit token; see credentials.
idpathintegerrequired, digitsExisting Pricing ID from the membership list.
autorenewbodyboolean recommendedneeded for changetrue enables; false disables. Null/omitted yields HTTP 400 user projection without this update.

Result

HTTP 200 JSON top-level resource-aware user plus subscriptions and teams. Use the resource-aware user fields and profile user projections, matching the existing renewal profile projection. No subscriptions_history, assigned_tickets or last_action addition. Membership projection there does not expose the relationship ID used internally.

Example: stop future renewal preference

Pricing 2001 already belongs to this member. The request changes the preference, not current access/expiry.

cURL

curl "${WALLKIT_API_BASE}/api/v1/user/subscriptions/2001" \
  -X POST \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}" \
  -H "Content-Type: application/json" \
  --data '{"autorenew":false}'

JavaScript

// Node.js 18+; built-in fetch.
async function main() {
  const url = new URL("/api/v1/user/subscriptions/2001", process.env.WALLKIT_API_BASE);
  const headers = {
    resource: process.env.RESOURCE_KEY,
    token: process.env.USER_TOKEN,
    "Content-Type": "application/json"
  };
  const response = await fetch(url, {
    method: "POST", headers, body: JSON.stringify({"autorenew":false})
  });
  console.log(response.status, await response.json());
}
main().catch(console.error);

Python

# Python 3; standard library only.
import json
import os
from urllib.error import HTTPError
from urllib.parse import urljoin
from urllib.request import Request, urlopen

url = urljoin(os.environ["WALLKIT_API_BASE"], "/api/v1/user/subscriptions/2001")
headers = {
    "resource": os.environ["RESOURCE_KEY"],
    "token": os.environ["USER_TOKEN"],
    "Content-Type": "application/json"
}
body = {'autorenew': False}
request = Request(url, data=json.dumps(body).encode("utf-8"), headers=headers, method="POST")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

HTTP 200 response excerpt:

{"id":7001,"subscriptions":[{"id":2001,"plan_id":1001,"autorenew":false}],"teams":[]}

The full resource-aware user projection contains identity/profile fields. Inspect the matching returned membership flag. Existing expiry is not cancelled by this request.

Consequential alternate: selected Pricing is not renewable

HTTP 400 response excerpt:

{"error":"incorrect_subscription","error_description":"This subscription is not renewable","req_guid":"example-request","id":7001,"subscriptions":[{"id":2001,"plan_id":1001,"autorenew":false}],"teams":[]}

This is the helper's enabling failure, followed by the current user projection. Do not treat the included user object as a successful update. Offer renewal only for a configured renewable Pricing.

Recovery

HTTPCode / responseCauseNext action
401auth_failed / auth_access_failInvalid identity/account/resource restrictions.Repair existing session/context or ask administrator about restrictions.
406incorrect_dataMissing JSON object.Send an autorenew JSON object.
404incorrect_subscription, Subscription not foundPricing missing or no current member relationship.Read existing memberships; select their Pricing ID.
400incorrect_user / incorrect_subscription / exception plus user fieldsRenewal helper throws.Inspect description/current state; check eligibility/configuration before another change.
400User projection, no handler errorautorenew omitted/null.Send true/false if a change is intended; this response did not update the flag.

Also registered as

POST /api/v1/user/subscription/{id} is the singular alias, with the same handler, inputs and result. It shares this canonical operation; it is not an additional renewal flow.

Next task

Read the returned account state and content decision if serving an article. For a new purchase, use checkout; turning on renewal is not a new purchase.

Full diagram

Use the arrow keys to scroll. Escape closes this view.

Search documentation

Enter at least 2 characters.

    ↑ ↓ move through results · Enter opens · Escape closes