Manage sponsorship records and slots

Choose the sponsor or recipient task using the intended member identity. Publisher Pricing, sponsorship, membership and slot are different records.

TaskOperation
List own sponsorshipsList own sponsorships
Read own sponsorshipRead own sponsorship
Update text/payer/renewal preferencesUpdate text/payer/renewal preferences
List parent sponsorship slotsList parent sponsorship slots
Read one owned sponsorship slotRead one owned sponsorship slot
Invite or notify a slot recipientInvite or notify a slot recipient
Clear a multi-seat slotClear a multi-seat slot

Recipient member tasks

Use the intended recipient’s active member token and resource context. Invitation listing matches the member’s email. Activation and turning off sponsor payment use different checks; read the selected operation.

TaskOperation
List email-matched invitation slotsList email-matched invitation slots
Activate a supplied slot codeActivate a supplied slot code
Turn off sponsor payment for a giftTurn off sponsor payment for a gift

Example clients and synthetic values follow response conventions.

Member and record context

All documented sponsorship actions require an active member and valid resource via token/resource headers; configured Firebase context follows the integration. Sponsor list/detail/update and slot list/detail/invitation select the current sponsor and the Pricing’s Plan resource through the parent sponsorship. These checks do not filter parent expiry/activation or slot activation. Clear and recipient actions have separate checks described with their operations. No administrator role or universal recipient-email verification follows from route prefixes.

List the current sponsor’s sponsorships

GET /api/v1/sponsor/sponsored-subscriptions

Inspect existing sponsorship records owned by the current person.

Before you call

Use member/record context. Selection joins configured Pricing/Plan, requires sponsor_id=current user and Plan.resource_id=selected resource. There is no active/expiry/activation filter. Records sort created_at descending, without a secondary tie order or pagination. No handler-specific payment/account mutation.

Request

Bodyless. No pagination/filter parameters are implemented.

NameLocationType / requirementMeaning
resource, tokenheadersrequired existing member contextSelected resource and owning sponsor identity.

Result

HTTP 200 JSON:

FieldTypeMeaning
itemsarray of expanded sponsor recordsEmpty [] possible. Mapper failures can leave partial items/[]; first associated membership summary is not every slot’s state.

Example: Inspect sponsor 4001’s existing sponsorship 8001

Use sponsor 4001’s member context to list existing sponsorships in the selected Pricing Plan’s resource. The excerpt shows parent 8001 linked to Pricing 2001; it creates neither a sponsorship nor a slot.

curl "${WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions`, {
  method: "GET", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN }
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/sponsor/sponsored-subscriptions",
    headers={"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"]}, method="GET")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

Synthetic HTTP 200 excerpt; other defined fields omitted:

{
  "items": [
    {
      "id": 8001,
      "sponsor_id": 4001,
      "subscription_id": 2001,
      "slots": []
    }
  ]
}

Consequential alternate

No selected sponsor/resource records gives HTTP 200 excerpt:

{
  "items": []
}

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member context fails.Resolve intended sponsor member identity.
404resource_not_existsResource missing/unresolved.Check supplied resource context.
409sponsor_subscriptions_errorQuery/general failure; exception message or Get sponsor subscriptions has failed.Ask integration owner to inspect owned records and Pricing/Plan relations.

Next task

Use the returned sponsorship ID for detail or slots.

Read one sponsorship owned by the current sponsor

GET /api/v1/sponsor/sponsored-subscriptions/{id}

Resolve an existing parent sponsorship and its nested slot/account summaries.

Before you call

Use member/record context. Integer-sanitized ID must be nonempty. Selection includes parent ID/current sponsor/Plan resource; no expiry or activation restriction. Missing/other-sponsor/wrong-resource parent returns HTTP 404. No action-specific writes.

Request

Bodyless. No pagination/filter parameters are implemented.

NameLocationType / requirementMeaning
resource, tokenheadersrequired existing member contextSelected resource and owning sponsor identity.
idpathrequired nonempty integer-sanitized valueSponsorship ID, not slot ID. Route itself has no digits constraint.

Result

HTTP 200 JSON:

FieldTypeMeaning
itemexpanded sponsor record, possibly partial/[]Selected sponsorship with sponsor/Pricing/slots and first-membership summary. Not an access or payment decision.

Example: Inspect sponsorship 8001 with its separate Pricing ID

Sponsor 4001 reads parent sponsorship 8001. The returned subscription_id 2001 identifies its configured Pricing, not the parent record or an individual membership.

curl "${WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/8001" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/8001`, {
  method: "GET", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN }
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/sponsor/sponsored-subscriptions/8001",
    headers={"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"]}, method="GET")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

Synthetic HTTP 200 excerpt:

{
  "item": {
    "id": 8001,
    "sponsor_id": 4001,
    "subscription_id": 2001,
    "autorenew": null,
    "slots": []
  }
}

Consequential alternate

Parent absent or outside sponsor/resource selection: HTTP 404 excerpt:

{
  "error": "sponsor_subscription_error",
  "error_description": "Sponsor subscription not found"
}

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member context fails.Resolve intended sponsor member identity.
404resource_not_existsResource missing/unresolved.Check supplied resource context.
409invalid_idEmpty/zero integer-sanitized ID.Supply intended parent sponsorship ID.
404sponsor_subscription_errorParent absent/outside sponsor/resource selection.Check owning identity and Pricing Plan resource.
409sponsor_subscription_errorQuery/general failure.Reconcile related records with integration owner.

Next task

Choose parent update or slot list; parent membership summary is not a slot ID.

Update sponsorship text and payment preferences

PUT /api/v1/sponsor/sponsored-subscriptions/{id}

Change supported parent fields and first-associated membership renewal preferences.

Before you call

Use member/record context. The parent must match the current sponsor and the selected Pricing Plan’s resource. Supplied title/description must pass presence/length validation before string/trim filtering. Null or empty text is not an erase instruction; omitted fields are unchanged.

Changes run in this order, without an enclosing transaction:

  1. Save supplied text and attempt its update event.
  2. Save the parent’s is_paying_by_sponsor flag and attempt its event.
  3. Save the first associated membership’s autorenew flag and attempt its event.
  4. Save that membership’s is_allowed_next_subscription flag and attempt its event.

A strictly unchanged flag skips its step. The membership is selected by sponsored_subscription_id alone, without ordering or user/slot selection. These edits do not promise changes to every dependent membership.

Save results are unchecked. Membership saves attempt user/resource cache invalidation. No immediate charge, refund, membership deletion or expiry occurs. A later failure can follow earlier saved changes and events.

Request

Truthy JSON object required; Content-Type: application/json.

NameLocationType / requirementMeaning
resource, tokenheadersrequired existing member contextSelected resource and owning sponsor identity.
idpathrequired nonempty integer-sanitized valueSponsorship ID, not slot ID. Route itself has no digits constraint.
titleJSONoptional present nonempty string, max 128Trimmed display title.
descriptionJSONoptional present nonempty string, max 512Trimmed display description.
is_paying_by_sponsorJSONoptional boolean-filtered valueParent payer-selection preference, not settlement proof.
autorenewJSONoptional boolean-filtered valueFirst associated membership renewal flag.
is_allowed_next_subscriptionJSONoptional boolean-filtered valueFirst associated membership next-Pricing flag.

Result

HTTP 200 JSON:

FieldTypeMeaning
itemexpanded sponsor record, possibly partial/[]Selected sponsorship with sponsor/Pricing/slots and first-membership summary. Not an access or payment decision.

Example: Update sponsorship 8001 without treating preference as a charge

Sponsor 4001 changes parent 8001’s title and turns off the first associated membership’s renewal flag. This request does not change every slot’s membership or issue a charge/refund.

curl -X PUT "${WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/8001" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}" \
  -H "Content-Type: application/json" \
  --data-raw '{"title": "Example sponsor group", "autorenew": false}'
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/8001`, {
  method: "PUT", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN, "Content-Type": "application/json" },
  body: JSON.stringify({"title": "Example sponsor group", "autorenew": false})
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

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

Synthetic HTTP 200 excerpt:

{
  "item": {
    "id": 8001,
    "title": "Example sponsor group",
    "autorenew": false
  }
}

Consequential alternate

If supplied autorenew has no associated membership, the entity wraps its HTTP 404 lookup as HTTP 409 excerpt:

{
  "error": "sponsor_subscription_update_error",
  "error_description": "Update sponsor subscription relationship autorenew status has failed"
}

The earlier title save/event can already have happened; do not assume atomic rollback.

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member context fails.Resolve intended sponsor member identity.
404resource_not_existsResource missing/unresolved.Check supplied resource context.
400incorrect_dataFalsey/non-JSON body.Supply supported JSON object.
409invalid_id / invalid_title / invalid_descriptionID or supported text validation fails.Supply intended ID and nonempty bounded text.
404sponsor_subscription_update_errorOwned parent not found.Check sponsor/resource/parent ID.
409sponsor_subscription_update_errorText/payer/membership save/event or general failure.Read current parent/membership state before repeating.

Next task

Read parent detail and inspect intended membership flags. Content access and actual payment outcomes remain separate.

List slots for an owned sponsorship

GET /api/v1/sponsor/sponsored-subscriptions/{id}/slots

Inspect all slots belonging to one selected parent.

Before you call

Use member/record context. Parent ownership/Plan resource is checked first. Slot selection uses that parent ID and sorts created_at descending; no activation/recipient/expiry filter and no paginator. No action-specific writes.

Request

Bodyless. No pagination/filter parameters are implemented.

NameLocationType / requirementMeaning
resource, tokenheadersrequired existing member contextSelected resource and owning sponsor identity.
idpathrequired nonempty integer-sanitized valueSponsorship ID, not slot ID. Route itself has no digits constraint.

Result

HTTP 200 JSON:

FieldTypeMeaning
itemsarray of base slots[] possible; partial mapper output possible. No expanded recipient/parent.

Example: Find slot 9001 under sponsorship 8001

Sponsor 4001 lists slots using parent ID 8001. Slot 9001 has no bound recipient in this excerpt; keep its ID for a separate slot task.

curl "${WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/8001/slots" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/8001/slots`, {
  method: "GET", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN }
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/sponsor/sponsored-subscriptions/8001/slots",
    headers={"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"]}, method="GET")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

Synthetic HTTP 200 excerpt:

{
  "items": [
    {
      "id": 9001,
      "sponsored_subscription_id": 8001,
      "recipient_id": null,
      "recipient_email": null,
      "activated_at": null
    }
  ]
}

Consequential alternate

Owned parent with no slots: HTTP 200 excerpt:

{
  "items": []
}

An empty list does not create a slot or prove usable capacity.

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member context fails.Resolve intended sponsor member identity.
404resource_not_existsResource missing/unresolved.Check supplied resource context.
404sponsor_subscription_slots_errorOwned parent absent.Check sponsor/resource and parent ID.
409sponsor_subscription_slots_errorEmpty/zero integer-sanitized ID gives generic Get sponsor subscription slots has failed; query/general failure can use the same code.Supply intended parent ID; inspect related records if it persists.

Next task

Use the slot ID for slot detail, keeping the parent ID separate.

Read one slot under an owned sponsorship

GET /api/v1/sponsor/sponsored-subscriptions/slots/{id}

Read base slot state after checking ownership/resource through its parent.

Before you call

Use member/record context. Slot is initially fetched by its ID, then its parent sponsorship must pass current sponsor/Plan-resource selection. No activation/expiry restriction or action-specific writes.

Request

Bodyless. No pagination/filter parameters are implemented.

NameLocationType / requirementMeaning
resource, tokenheadersrequired existing member contextSelected resource and owning sponsor identity.
idpathrequired nonempty integer-sanitized valueSlot ID, not sponsorship ID. Route itself has no digits constraint.

Result

HTTP 200 JSON:

FieldTypeMeaning
itembase slot, possibly partial/[]No recipient or nested sponsorship expansion.

Example: Read slot 9001’s invitation state

Sponsor 4001 reads slot 9001 using the slot ID. The contact email and activation code are invitation state, not verified recipient identity or delivery proof.

curl "${WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/slots/9001" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/slots/9001`, {
  method: "GET", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN }
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/sponsor/sponsored-subscriptions/slots/9001",
    headers={"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"]}, method="GET")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

Synthetic HTTP 200 excerpt:

{
  "item": {
    "id": 9001,
    "sponsored_subscription_id": 8001,
    "recipient_email": "reader@example.com",
    "activation_code": "SLOT_ACTIVATION_CODE_PLACEHOLDER",
    "activated_at": null
  }
}

Consequential alternate

Slot not found: HTTP 404 excerpt:

{
  "error": "sponsor_subscription_slot_error",
  "error_description": "Slot not found"
}

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member context fails.Resolve intended sponsor member identity.
404resource_not_existsResource missing/unresolved.Check supplied resource context.
404sponsor_subscription_slot_errorSlot or selected owned parent not found.Check slot ID/current sponsor/Plan resource.
409sponsor_subscription_slot_errorEmpty/zero integer-sanitized ID gives generic Get sponsor subscription slot has failed; query/general failure can use the same code.Supply intended slot ID; inspect related records with owner.

Next task

Use base slot recipient/code/activation state to choose the intended invitation or clearing task; a readable slot is not proof of recipient access.

Invite or notify a sponsorship slot recipient

PUT /api/v1/sponsor/sponsored-subscriptions/slots/{id}/invitation

Store the intended recipient email and attempt configured notification events.

Before you call

Use member/record context. The slot’s parent must match the current sponsor and Pricing Plan resource. An activated slot rejects changes. recipient_email must be present and email-valid; the sanitized value is stored in lowercase without an explicit trim step.

Code behavior: changing a nonempty stored email to a different lowercase email generates a new unique 16-character activation code. An empty prior email or the same email retains the stored code. A same-email request can attempt notifications again; it is not deduplicated by a documented guarantee.

Save and notification: the save result is unchecked, then the slot is refreshed. Generic and gift/multi-seat invitation events are attempted afterward. An unsupported Pricing type or event failure can therefore follow an email change.

The action does not bind recipient_id, activate membership, set expiry or charge payment. There is no enclosing transaction or delivered-email guarantee.

Request

Truthy JSON object required, Content-Type: application/json.

NameLocationType / requirementMeaning
idpathrequired slot ID, integer-sanitized/castSlot record, not parent/Pricing/membership ID; no route digits constraint.
token, resourceheadersrequired existing contextActive owning sponsor and selected resource.
recipient_emailJSONrequired emailStored lowercase sanitized contact; not verified member ownership.

Result

HTTP 200 JSON:

FieldTypeMeaning
itembase slot, partial/[] possibleRefreshed invitation state, including stored code; no recipient/parent expansion or delivery receipt.

Example: Invite reader@example.com to slot 9001

Sponsor 4001 selects unactivated slot 9001 and stores reader@example.com as its contact. Notification events are attempted; membership activation remains a separate recipient task.

curl -X PUT "${WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/slots/9001/invitation" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}" \
  -H "Content-Type: application/json" \
  --data-raw '{"recipient_email": "reader@example.com"}'
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/slots/9001/invitation`, {
  method: "PUT", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN, "Content-Type": "application/json" },
  body: JSON.stringify({"recipient_email": "reader@example.com"})
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

body = {'recipient_email': 'reader@example.com'}
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/sponsor/sponsored-subscriptions/slots/9001/invitation",
    data=json.dumps(body).encode("utf-8"), headers={"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"], "Content-Type": "application/json"}, method="PUT")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

Synthetic HTTP 200 excerpt:

{
  "item": {
    "id": 9001,
    "sponsored_subscription_id": 8001,
    "recipient_email": "reader@example.com",
    "activation_code": "SLOT_ACTIVATION_CODE_PLACEHOLDER",
    "activated_at": null
  }
}

Consequential alternate

Already activated slot gives HTTP 409 excerpt:

{
  "error": "sponsor_subscription_slot_error",
  "error_description": "Sponsor subscription slot invitation has failed"
}

Changing recipient requires a different intended clearing task where eligible; this request does not transfer an activated membership.

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member missing.Use intended sponsor identity/context.
404resource_not_existsResource unresolved.Check supplied resource key.
404sponsor_subscription_slot_errorSlot or owned parent absent.Check slot/parent ownership and resource.
409sponsor_subscription_slot_error; Sponsor subscription slot invitation has failedEmpty/zero ID, invalid/missing email or falsey body; also store/event/general failure.Supply valid JSON recipient_email and slot ID; inspect saved email/code before repeating after failure.
409sponsor_subscription_slot_error; Sponsor subscription slot invitation has failedActivation marker nonempty; the outward message is generic.Inspect intended existing recipient/membership; invitation is not reassignment.

Next task

Use the existing configured delivery flow for the intended recipient to obtain the activation code. Code in this sponsor response is a credential, not proof of delivery or verified recipient identity.

Clear an owned multi-seat sponsorship slot

PUT /api/v1/sponsor/sponsored-subscriptions/slots/{id}/clear

Reset slot recipient/invitation state and attempt deletion of its first linked membership.

Before you call

Use active sponsor/resource context. The slot ID is integer-cast. Inside a database transaction, the Pricing Plan’s resource and parent sponsor_id must strictly match the supplied context. Pricing must be multi-seat; gift slots are excluded. There is no explicit parent-expiry or slot-active guard.

Slot reset: the action clears recipient_id, recipient_email and activated_at, generates a fresh activation code and attempts an unchecked save.

Membership cleanup: it deletes the first membership found by sponsored_subscription_slot_id and writes history. Neither result is checked; this does not remove every matching or dependent membership. Deletion attempts user/resource cache invalidation. If the Plan resource enables auto_clear_content_views and the membership has a user ID, the deletion hook also attempts removal of all that user’s content-view records without resource filtering. It does not delete the user or issue a refund.

Completion: the action commits and prepares success/item, then attempts a slot-update event outside its error-handling block. An event failure can follow committed writes without a stable action-specific error response. Local rollback does not guarantee reversal of nested, hook or external effects.

Request

Bodyless; no action JSON fields consumed.

NameLocationType / requirementMeaning
idpathrequired slot ID, integer-sanitized/castSlot record, not parent/Pricing/membership ID; no route digits constraint.
token, resourceheadersrequired existing contextActive owning sponsor and selected resource.

Result

HTTP 200 JSON:

FieldTypeMeaning
successboolean, true on completed pathControl-flow acknowledgement; unchecked writes are not certified.
itembase slot, partial/[] possibleReset recipient/code state, not deleted user or refund receipt.

Example: Clear multi-seat slot 9001 for intended reuse

Sponsor 4001 clears slot 9001 under a multi-seat Pricing. This resets recipient/code state and attempts first-linked membership cleanup; the gift branch is excluded.

curl -X PUT "${WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/slots/9001/clear" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/sponsor/sponsored-subscriptions/slots/9001/clear`, {
  method: "PUT", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN }
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/sponsor/sponsored-subscriptions/slots/9001/clear",
    headers={"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"]}, method="PUT")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

Synthetic HTTP 200 excerpt:

{
  "success": true,
  "item": {
    "id": 9001,
    "sponsored_subscription_id": 8001,
    "recipient_id": null,
    "recipient_email": null,
    "activation_code": "NEW_SLOT_CODE_PLACEHOLDER",
    "activated_at": null
  }
}

Consequential alternate

Gift/non-multi-seat Pricing gives HTTP 409 excerpt:

{
  "error": "sponsored_subscription_type",
  "error_description": "Available to clear only multi-seat slots"
}

The transaction catch attempts rollback; this action does not offer a gift-clear branch.

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member missing.Use intended sponsor identity/context.
404resource_not_existsResource unresolved.Check supplied resource key.
409sponsored_subscription_typePricing is not multi-seat.Use this task only for intended multi-seat slot.
409sponsored_subscription_sponsorStrict parent sponsor mismatch.Use owning sponsor identity.
409sponsor_clear_slot_error; Clear slot has failedSlot/related records missing, resource mismatch or caught save/history/general failure.Reconcile slot/membership/history and selected resource before repeating.
UnspecifiedNo stable action-specific event errorPostcommit update event throws outside catch.Inspect committed state and notification attempt before repeating.

Next task

Inspect slot detail and account/access state separately. If a new recipient is intended, invite after reconciling clearing, not as an automatic chained operation.

List invitation slots matching the current member’s email

GET /api/v1/recipient/sponsored-subscriptions/slots/invitations

Find pending stored invitations addressed to the current person’s email.

Before you call

Use member context. Selection compares recipient_email to current user.email exactly, joins Pricing Plan resource, requires activation_code IS NOT NULL, activated_at IS NULL and parent expired_at IS NULL. It does not require recipient_id=current user or check parent end dates, other active flags or future activation success. No ordering or pagination specified. No handler-specific account writes.

Request

Bodyless; no action pagination/filter parameters implemented.

NameLocationType / requirementMeaning
resource, tokenheadersrequired existing contextSelected resource and active intended recipient member.

Result

HTTP 200 JSON:

FieldTypeMeaning
itemsarray of recipient invitation slots[] possible. Nested parent sponsor/Pricing/summary, no recipient expansion or nested slots. Mapper failures can return partial items/[].

Example: Find reader@example.com’s pending slot 9001

Use reader@example.com’s active member context to list email-matched pending invitations. Slot 9001 belongs to parent 8001; finding it does not reserve or activate it.

curl "${WALLKIT_API_BASE}/api/v1/recipient/sponsored-subscriptions/slots/invitations" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/recipient/sponsored-subscriptions/slots/invitations`, {
  method: "GET", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN }
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/recipient/sponsored-subscriptions/slots/invitations",
    headers={"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"]}, method="GET")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

Synthetic HTTP 200 excerpt:

{
  "items": [
    {
      "id": 9001,
      "recipient_email": "reader@example.com",
      "activation_code": "SLOT_ACTIVATION_CODE_PLACEHOLDER",
      "sponsored_subscription": {
        "id": 8001,
        "subscription_id": 2001
      }
    }
  ]
}

Consequential alternate

No matching pending invitations: HTTP 200 excerpt:

{
  "items": []
}

An existing supplied code follows a separate lookup; listing absence is not proof that code activation will reject it.

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member context missing.Resolve intended recipient identity/context.
404resource_not_existsResource unresolved.Check supplied resource key.
409sponsor_subscription_slot_errorRecipient query/general failure.Ask integration owner to inspect stored email, resource and pending invitation records.

Next task

If accepting an intended invitation, use its activation code for activation with the intended member identity; that action has different checks.

Activate a sponsorship slot using its code

PUT /api/v1/recipient/sponsored-subscriptions/slots/activate

Attempt the selected slot’s membership activation for the current active person.

Before you call

Use member context and the existing issuer-provided code. It must remain nonempty after string/trim filtering. Code lookup is exact and initially has no email/resource predicate.

Acceptance checks: the slot must not have an activation marker, and its Pricing Plan must strictly match the selected resource. recipient_id is compared with the current member only when already nonempty. The action does not compare recipient_email or reject a parent expired_at marker. An unbound slot can therefore pass the identity check for a member who holds the code; email-matched listing does not strengthen this guard.

Only gift and multi-seat Pricings are supported:

  • Gift: creates or replaces recipient membership with sponsorship/slot IDs. Pricing trial settings are checked first; the shared helper applies trial only if the person’s current/history trial eligibility also passes. Parent activated_at is then saved.
  • Multi-seat: requires a first parent membership with the sponsorship ID, null parent_id and null user_id. Recipient membership uses that parent ID and slot ID, null sponsored_subscription_id, the copied parent end date and trial=false.

The membership helper can replace prior memberships, write history, stop/clear other sponsorships and attempt cache, content-view, event and synchronization effects. Deletion hooks can conditionally clear user content-view records across resources.

The slot’s recipient and activation time are set, and its code is cleared, without checking save success. Gift parent save is also unchecked. Sponsor/recipient events follow. There is no transaction covering the entire action; nested helper transactions do not make later slot, parent or event writes atomic or safe to repeat.

Request

Truthy JSON object required, Content-Type: application/json.

NameLocationType / requirementMeaning
resource, tokenheadersrequired existing contextSelected resource and active intended recipient member.
activation_codeJSONrequired nonempty stringExisting slot code; string/trim-sanitized. Not an invite/member token.

Result

HTTP 200 JSON:

FieldType / presenceMeaning
successboolean, true on completed pathControl-flow acknowledgement, not checked persistence/payment/access proof.
itemexpanded recipient slot, possibly partial/[]; includes recipient plus nested parent with sponsor/Pricing/first-membership summary, no nested slotsSlot/account projection after attempted activation.

Example: Accept slot 9001 as intended recipient 4002

Use intended recipient 4002’s active member context and the supplied slot activation code. The configured Pricing chooses the gift or multi-seat branch; email-matched discovery and code activation have different checks.

curl -X PUT "${WALLKIT_API_BASE}/api/v1/recipient/sponsored-subscriptions/slots/activate" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}" \
  -H "Content-Type: application/json" \
  --data-raw '{"activation_code": "SLOT_ACTIVATION_CODE_PLACEHOLDER"}'
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/recipient/sponsored-subscriptions/slots/activate`, {
  method: "PUT", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN, "Content-Type": "application/json" },
  body: JSON.stringify({"activation_code": "SLOT_ACTIVATION_CODE_PLACEHOLDER"})
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

body = {'activation_code': 'SLOT_ACTIVATION_CODE_PLACEHOLDER'}
request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/recipient/sponsored-subscriptions/slots/activate",
    data=json.dumps(body).encode("utf-8"), headers={"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"], "Content-Type": "application/json"}, method="PUT")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

Synthetic HTTP 200 excerpt:

{
  "success": true,
  "item": {
    "id": 9001,
    "recipient_id": 4002,
    "recipient_email": "reader@example.com",
    "activation_code": null,
    "sponsored_subscription": {
      "id": 8001,
      "subscription_id": 2001
    }
  }
}

Consequential alternate

A consumed/cleared code that no longer matches gives HTTP 404 excerpt:

{
  "error": "sponsor_subscription_slot_error",
  "error_description": "Slot not found"
}

Nulling code is attempted, not checked. A retained code with a nonempty activation marker instead rejects as already activated; do not promise replay success.

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member context missing.Resolve intended recipient identity/context.
404resource_not_existsResource unresolved.Check supplied resource key.
400incorrect_dataFalsey/non-JSON body.Supply supported JSON object.
409invalid_activation_codeEmpty code after sanitization.Supply intended issuer-provided code.
404sponsor_subscription_slot_error; Slot not foundCode lookup absent.Check supplied code and whether it was cleared/consumed.
409sponsor_subscription_slot_errorActivated slot, strict resource mismatch, bound recipient mismatch, unsupported type, missing parent membership or wrapped activation failure.Inspect slot/parent/membership/current identity before repeating; prior changes may exist.
409sponsor_subscription_slot_error; Activate sponsored subscription slot has failedGeneral/event failure.Reconcile membership/slot/parent and attempted notification state.

Next task

Inspect your memberships and obtain the separate content-access decision. If payment preference needs changing for a gift, read sponsor payment off; activation is not a charge receipt.

Turn off sponsor payment for a gift slot

PUT /api/v1/recipient/sponsored-subscriptions/slots/{id}/sponsor/turn-off

Attempt to disable the parent gift sponsorship’s payer flag.

Before you call

Use active member/resource context. The slot is fetched without an initial owner/email predicate. Pricing must be gift, and its Plan resource must strictly match. The current person is checked against recipient_id only when that field is nonempty. Email, activation time and parent expiry are not checked.

Payer change: an already-false parent is_paying_by_sponsor flag rejects the request. Otherwise the helper sets it false and attempts an unchecked save. General helper failures can be logged and swallowed.

Later effects: mapping and sponsor/recipient event attempts follow without an enclosing transaction. An unbound slot can pass the earlier identity check, then fail the recipient-empty event check after the parent mutation attempt. An error therefore does not prove unchanged state.

This action does not refund, expire or delete membership, configure a recipient payment source or charge payment. A later charging helper uses the flag to choose sponsor versus member; it does not guarantee successful future collection.

Request

Bodyless; no action JSON fields consumed.

NameLocationType / requirementMeaning
resource, tokenheadersrequired existing contextSelected resource and active intended recipient member.
idpathrequired slot ID, integer-castGift slot ID, not parent/Pricing/membership ID; no route digits constraint.

Result

HTTP 200 JSON:

FieldTypeMeaning
itemexpanded recipient slot, possibly partial/[]; includes recipient plus nested parent with sponsor/Pricing/first-membership summary, no nested slotsParent payer preference after attempted save; no success flag or payment receipt.

Example: Stop sponsor payment preference for recipient 4002’s gift 9001

Recipient 4002 selects gift slot 9001 with their own member context to turn off its parent’s sponsor payer flag. This does not refund or delete their membership or configure a recipient payment source.

curl -X PUT "${WALLKIT_API_BASE}/api/v1/recipient/sponsored-subscriptions/slots/9001/sponsor/turn-off" \
  -H "resource: ${RESOURCE_KEY}" \
  -H "token: ${USER_TOKEN}"
const response = await fetch(`${process.env.WALLKIT_API_BASE}/api/v1/recipient/sponsored-subscriptions/slots/9001/sponsor/turn-off`, {
  method: "PUT", headers: { "resource": process.env.RESOURCE_KEY, "token": process.env.USER_TOKEN }
});
console.log(response.status, await response.json());
import os, json
from urllib.request import Request, urlopen
from urllib.error import HTTPError

request = Request(os.environ["WALLKIT_API_BASE"] + "/api/v1/recipient/sponsored-subscriptions/slots/9001/sponsor/turn-off",
    headers={"resource": os.environ["RESOURCE_KEY"], "token": os.environ["USER_TOKEN"]}, method="PUT")
try:
    with urlopen(request) as response:
        print(response.status, json.load(response))
except HTTPError as error:
    print(error.code, json.load(error))

Synthetic HTTP 200 excerpt:

{
  "item": {
    "id": 9001,
    "recipient_id": 4002,
    "sponsored_subscription": {
      "id": 8001,
      "is_paying_by_sponsor": false
    }
  }
}

Consequential alternate

Unbound recipient can reach a post-mutation event error: HTTP 409 excerpt:

{
  "error": "sponsor_subscription_slot_error",
  "error_description": "Sponsored subscription slot recipient is empty"
}

The parent flag may already have changed. Reconcile parent/account state before repeating; this is not atomic failure.

Recovery

HTTPAPI codeCauseRecovery
401auth_failed / auth_access_failActive member context missing.Resolve intended recipient identity/context.
404resource_not_existsResource unresolved.Check supplied resource key.
404sponsor_subscription_slot_error; Slot not foundSlot missing.Check intended gift slot ID.
409sponsor_subscription_slot_errorNot gift, wrong resource/bound recipient, already-disabled payer, missing relations or event exception.Inspect gift/recipient/parent payer state and intended member identity.
409sponsor_subscription_slot_error; Sponsored subscription slot recipient is emptyEvent sees no recipient after mutation attempt.Reconcile parent payer flag; do not assume rollback.
409sponsor_subscription_slot_error; Activate sponsored subscription slot has failedGeneral exception; message mentions activation although this is payer-off.Inspect parent payer state and event attempt before repeating.

Next task

Read account/membership and access state separately. Disabled sponsor payment does not delete membership or issue a refund; any future collection needs its own configured billing flow.

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