Credit-Based Subscriptions - Wallets

Prev Next

Overview

A credit-based subscription gives your customers a wallet of credits that they spend to unlock individual pieces of content — an article, an e-paper edition, a webinar. The customer buys a credit-based offer once, receives a balance of credits, and then pays for each item with credits instead of money.

This guide covers the part of the integration that is not handled automatically for you: what your website must do when a customer clicks a paywalled article and wants to redeem a credit to read it. Configuring the offer and the wallet in the Merchant Backend is covered in the articles under Before you begin; this guide starts where those leave off.

Note

Redeeming a credit is a server-to-server operation. Frisbii Media does not ship a ready-made "spend credits" button in the Checkout or JS-SDK paywall. Your backend calls the wallet API, and your application decides what the customer may read. This gives you full control over the paywall experience, but the access logic described below is your responsibility to implement.

How the pieces fit together

Concept

What it is

Where it is created

Credit-based offer

The offer the customer buys (single product or subscription). Subscription types: CREDIT_BASED, CREDIT_TRIGGER_BASED, TIME_CREDIT_BASED.

Merchant Backend → Offers

Wallet

The credit account, identified by a uniqueId. Holds the balance (availableCreditCount).

Merchant Backend → Products, linked to the offer

Credit

A unit in the wallet. One purchase adds the offer's consumption units to the wallet.

Filled automatically on purchase/recharge

Redemption

Spending credits from the wallet — the POST /wallets/use call.

Your backend (this guide)

Access

The customer being allowed to read the item after redemption.

Your application (this guide)

The end-to-end flow for a single article looks like this:

sequenceDiagram
    participant C as Customer (browser)
    participant P as Your paywall (JS-SDK / SSO)
    participant S as Your backend
    participant FM as Frisbii Media API

    Note over C,FM: Setup — done earlier
    C->>FM: Buy credit-based offer (Checkout)
    FM-->>FM: Fill wallet (availableCreditCount up)

    Note over C,FM: Runtime — redeeming a credit
    C->>P: Click paywalled article
    P->>FM: SSO login
    FM-->>P: Authenticated session
    P->>S: Request article (with SSO session)
    S->>FM: GET /wallets/{customerId}/{uniqueId}
    FM-->>S: availableCreditCount
    alt Already unlocked
        S-->>C: Serve article (no credit spent)
    else Enough credits
        S-->>C: Show "Read for 1 credit"
        C->>S: Confirm
        S->>FM: POST /wallets/use
        FM-->>S: 200 OK (balance down, usage logged)
        S->>S: Record unlock (or create access right)
        S-->>C: Serve article
    else Not enough credits
        S-->>C: Offer top-up / purchase
    end

The setup steps (buying the offer, filling the wallet) are covered by existing documentation. The runtime steps — SSO, balance check, redemption, and serving the article — are what this guide documents.


Before you begin

  • You have created a wallet and a credit-based offer, and you know the wallet's uniqueId. See Credit-Based Offers, Credit-based subscription and Wallets.

  • Customers can already buy the offer through your Checkout integration. A completed purchase fills the wallet automatically.

  • You have a server-side API access token with the Wallets access group enabled. See API Access Tokens. The token is sent in the X-plenigo-token header and must never be exposed in the browser.

  • Your paywall identifies the logged-in customer through SSO , so your backend can resolve the customer's Frisbii Media customerId.


Step 1: Identify the customer through SSO

Credit redemption is tied to a specific customer, so your backend needs the customer's Frisbii Media customerId before it can touch the wallet.

  1. Log the customer in — Use the JS-SDK SSO or Cookie-based SSO on your paywall so the visitor has an authenticated Frisbii Media session.

  2. Resolve the customerId — From the SSO session (or, if you run External User Management, from your own mapping of your user to the Frisbii Media customer), obtain the customerId on your server.

Do the wallet calls from your server, not the browser

The wallet endpoints are authenticated with your merchant API token. Never call them from client-side JavaScript, and never ship the token to the browser. The browser's job is only to authenticate the customer (SSO) and to trigger a request to your backend.

Step 2: Read the wallet balance

Before you show the "Read for 1 credit" prompt, check how many credits the customer has. Query the customer's wallet by its uniqueId.

Request

GET /api/v3.0/wallets/{customerId}/{uniqueId}
Host: api.frisbii-media.com
X-plenigo-token: {your_api_access_token}
curl -X GET \
  "https://api.frisbii-media.com/api/v3.0/wallets/CUSTOMER_ID/my-article-wallet" \
  -H "X-plenigo-token: {your_api_access_token}"

Response (200 OK)

{
  "customerCreditWalletId": 480123,
  "customerId": "CUSTOMER_ID",
  "uniqueId": "my-article-wallet",
  "title": "Article credits",
  "availableCreditCount": 8,
  "creditValidityTimeStart": "2026-07-01T09:00:00Z"
}

Use availableCreditCount to drive your paywall:

  • availableCreditCount >= creditsNeeded — show the "Read for 1 credit" prompt.

  • availableCreditCount < creditsNeeded — show a top-up / buy path (start a new Checkout for the credit-based offer) instead.

To display history or reconcile, you can also use GET /api/v3.0/wallets/ (all wallets for the customer), GET /api/v3.0/wallets/creditsUsed, and GET /api/v3.0/wallets/creditsUploaded.

Step 3: Redeem the credit

When the customer confirms, your backend spends credits from the wallet with a single call. This is the core of the integration.

Request

POST /api/v3.0/wallets/use
Host: api.frisbii-media.com
X-plenigo-token: {your_api_access_token}
Content-Type: application/json
{
  "customerId": "CUSTOMER_ID",
  "uniqueId": "my-article-wallet",
  "creditsUsed": 1,
  "reason": "article:2026-07-29-market-outlook",
  "category": "article"
}

Field

Required

Notes

customerId

Yes

The Frisbii Media customer ID.

uniqueId

Yes

The wallet's unique ID (the credit account to debit) — not an article ID.

creditsUsed

Yes

Number of credits to spend. Min 1, max 100000. Usually 1.

reason

Yes

Free text, max 100 characters. This is the only place the redeemed item is recorded — put your own article reference here (see the caveat below).

category

No

Free text, max 100 characters. Useful for grouping/reporting (e.g. article, epaper, webinar).

On success (200 OK) Frisbii Media atomically:

  • decrements availableCreditCount by creditsUsed,

  • writes a credit usage record (visible via GET /wallets/creditsUsed and in the Wallet Change History), and

  • if the balance reaches 0 on a subscription wallet, schedules the subscription's next billing so the wallet recharges according to its configured recharge type.

On insufficient balance (400 Bad Request) the response carries the message "Wallet does not contain enough credits." (Frisbii Media error entity 102000, detail code 1). Handle it as "cannot unlock" and route the customer to a top-up / purchase.

Step 4: Grant access and serve the article

This is the step that Frisbii Media leaves to you, and the reason the redemption flow can feel "missing".

Important: redeeming a credit does not create access to a specific article

  • The /wallets/use call debits the wallet and logs a usage record. It does not store which article was unlocked (only your free-text reason/category), and it does not create an access right for that article.

  • Every call to /wallets/use spends credits again. If the customer reloads the page or clicks twice, you will charge a second credit unless you prevent it.

Your application must therefore (a) remember what the customer has unlocked and (b) enforce that on every subsequent visit.

You have two ways to implement access. Choose one and apply it consistently.

Option A — Keep the unlock record in your own system (simplest)

  1. Before redeeming, check your own store for an existing (customerId, articleId) unlock. If it exists, serve the article and skip the /wallets/use call — the customer already paid.

  2. After a successful redemption, persist the (customerId, articleId) unlock (and, ideally, the returned usage record) in your database.

  3. On every future request for that article, serve it based on your stored unlock, not by calling /wallets/use again.

This keeps all article-level logic on your side and is the most direct fit for the wallet API.

If you already gate content with Access Rights and Check Access, turn each successful redemption into a durable access right so the same hasAccess check protects both money-based and credit-based content.

  1. After /wallets/use returns 200, create an access right for the article, using a stable accessRightUniqueId per item (for example, the same identifier you use elsewhere for that article):

    POST /api/v3.0/accessRights/{customerId}/
    X-plenigo-token: {your_api_access_token}
  2. On every future visit, validate access with the standard check — no wallet call needed:

    GET /api/v3.0/accessRights/{customerId}/hasAccess?accessRightUniqueIds=article:2026-07-29-market-outlook
    { "accessGranted": true }

Tip: make redemption idempotent

With either option, check "does the customer already have access to this item?" before calling /wallets/use. That single guard prevents double-charging on reloads, retries and double-clicks — the most common integration bug with credits.

Endpoint reference

Base URL (production): https://api.frisbii-media.com/api/v3.0. Confirm the host for your environment in API versions. Authentication: X-plenigo-token header, merchant API access token with the Wallets access group (and Access Rights for Option B).

Operation

Method & path

Purpose

Read a wallet

GET /wallets/{customerId}/{uniqueId}

Get availableCreditCount for one wallet.

List wallets

GET /wallets/

All wallets (paginated).

Redeem credits

POST /wallets/use

Spend credits from a wallet.

Credit usage history

GET /wallets/creditsUsed

Audit spent credits.

Credit upload history

GET /wallets/creditsUploaded

Audit added credits.

Add credits manually

POST /wallets/upload

Top up a wallet outside a purchase.

Refill wallets

POST /wallets/refillWallets/{uniqueId}

Trigger the configured recharge.

Create access right

POST /accessRights/{customerId}/

(Option B) Grant durable article access.

Check access

GET /accessRights/{customerId}/hasAccess

(Option B) Validate access on later visits.

Troubleshooting

Symptom

Likely cause

400 "Wallet does not contain enough credits."

availableCreditCount is below creditsUsed. Read the balance first and route to a top-up.

404 on the wallet

Wrong uniqueId, wrong customerId, or the customer never bought a credit-based offer (no wallet yet).

Customer charged twice for one article

No idempotency guard — you called /wallets/use again on reload. Add the "already has access?" check from Step 4.

401/403

Token missing the Wallets access group, wrong environment token, or the token was sent from the browser.