Skip to content

Alibaba Token Plan: personal (Solo) subscriptions render no quota rows — ProductCode is hardcoded to the Teams plan #2370

Description

@LeoLin990405

Summary

On a personal (Solo) Alibaba Token Plan subscription, the Alibaba Token Plan card authenticates fine but renders no quota rows — primary, secondary and tertiary are all null. The card shows only the provider title and Plan: Token Plan.

The subscription-summary request is hardcoded to the Teams product code, and the console returns an empty payload for a Solo subscription.

Environment

  • CodexBar 0.45.0 (also reproduced on 0.41.0)
  • macOS, menu-bar app + codexbar CLI
  • Alibaba Model Studio / Bailian, region cn-beijing
  • Subscription: Token Plan "Pro 套餐", personal (Solo), auto-renew on
  • Auth: cookie (web), working

Observed

codexbar usage --provider alibabatokenplan --format json (redacted):

{
  "usage": {
    "identity": { "providerID": "alibabatokenplan", "loginMethod": "TOKEN PLAN" },
    "primary": null,
    "secondary": null,
    "tertiary": null,
    "updatedAt": "2026-07-21T09:03:25Z"
  },
  "source": "web",
  "provider": "alibabatokenplan"
}

Text output is just:

== Alibaba Token Plan (web) ==
Plan: Token Plan

Auth itself is healthy — debug log shows the sec_token being resolved and a 200 response:

info …alibaba-token-plan: bodyBytes=225 userInfoHost=bailian.console.aliyun.com  Resolved Alibaba Token Plan sec_token from user info
info …alibaba-token-plan: bodyBytes=407 contentType=application/json;charset=UTF-8 status=200  Alibaba Token Plan HTTP response

So the provider reaches the API and gets a 200 — the 407-byte body simply carries no quota fields.

Root cause (source-level)

AlibabaTokenPlanUsageFetcher builds the subscription-summary request with a product code that is hardcoded to the Teams plan:

Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanAPIRegion.swift

public var tokenPlanProductCode: String {
    switch self {
    case .international:
        "sfm_tokenplanteams_dp_intl"
    case .chinaMainland:
        "sfm_tokenplanteams_dp_cn"
    }
}

Sources/CodexBarCore/Providers/Alibaba/AlibabaTokenPlanUsageFetcher.swift:284

let paramsObject = ["ProductCode": region.tokenPlanProductCode]

…which is then posted as action=GetSubscriptionSummary&product=BssOpenAPI-V3.

git grep -c "tokenplansolo\|solo_public" Sources/0 matches. There is no Solo/personal code path.

Evidence that this account is a Solo subscription

Captured from the Bailian console's own calls on
#/efm/subscription/token-plan/personal (values redacted):

action=QueryAvailableInstances&product=BssOpenApi

{
  "Data": {
    "TotalCount": 1,
    "InstanceList": [
      {
        "InstanceID": "sfm_tokenplansolo_public_cn-<redacted>",
        "ProductType": "sfm_tokenplansolo_public_cn",
        "ProductCode": "sfm",
        "SubscriptionType": "Subscription",
        "Status": "Normal",
        "RenewStatus": "AutoRenewal",
        "EndTime": "2026-08-21T16:00:00Z"
      }
    ]
  },
  "Code": "Success"
}

The instance is sfm_tokenplan**solo**_public_cn, while CodexBar asks about
sfm_tokenplan**teams**_dp_cn.

Notably, the console's own summary call — with the Teams product code — also comes back empty for this account:

action=GetSeatSubscriptionSummary&product=BssOpenAPI-V3&params={"ProductCode":"sfm_tokenplanteams_dp_cn"}

{ "Data": {}, "Code": "Success", "Success": true }

Meanwhile the console page itself does render the two quota windows CodexBar models well — 5小时用量 (5-hour) and 7天用量 (7-day), both with 0/50/90/100% markers, plus "最后统计时间" (last aggregation time).

What is verified vs. not

Verified:

  • Cookie auth and sec_token resolution work; the summary endpoint returns HTTP 200.
  • CodexBar sends the Teams product code on a Solo subscription.
  • The Teams-code summary call returns an empty Data object for this account.
  • There is no Solo/personal product code anywhere in the source.
  • Result: all three rate windows are nil, so the card renders no usage.

Not verified (being explicit rather than guessing):

  • I have not confirmed that simply substituting the Solo product code would populate the quota fields. This subscription was created today and currently shows 0% on both the 5-hour and 7-day windows, so an empty/zero response is not yet distinguishable from a wrong-product-code response. I'd rather report the mismatch than assert a fix I can't demonstrate.

I'm happy to re-test and post a redacted before/after once this account has accumulated real usage, if that's useful.

Possible directions

Rather than hardcoding a second constant, the product code could be discovered:

  1. Call QueryAvailableInstances (product=BssOpenApi) and read ProductType from the returned instance, then use it for the summary request — this covers Solo, Teams and any future SKU.
  2. Or try the Teams code and fall back to the Solo code when Data comes back empty.
  3. Whether the Solo quota actually lives behind GetSubscriptionSummary at all still needs confirming — the console's Solo page may source the 5-hour/7-day windows from a different call.

Happy to help verify any of these against a live Solo account.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions