Skip to content

TypeScript SDK has no apiToken field anywhere — Metaculus authentication is entirely unreachable #2204

Description

@realfishsam

Gap

Metaculus requires a token on every call — per core's own comments, "Metaculus no longer allows unauthenticated access to any endpoint." The sidecar factory only ever reads credentials.apiToken for this venue, never apiKey. The TypeScript SDK's ExchangeOptions interface has no apiToken field anywhere, and Exchange.getCredentials() never populates one — so the TypeScript Metaculus class has no code path to authenticate at all. The Python SDK does this correctly via a dedicated api_token parameter.

Core

core/src/server/exchange-factory.ts:110-114:

case "metaculus":
    return new MetaculusExchange({
        apiToken:
            credentials?.apiToken || process.env.METACULUS_API_TOKEN,
    });

core/src/exchanges/metaculus/index.ts:60-65this.apiToken = credentials?.apiToken; (apiKey is never read for this venue).

TypeScript SDK

Missing — sdks/typescript/pmxt/client.ts:233-302 (ExchangeOptions interface has no apiToken member) and client.ts:482-493:

protected getCredentials(): ExchangeCredentials | undefined {
    if (!this.apiKey && !this.apiSecret && !this.privateKey) return undefined;
    return { apiKey: this.apiKey, apiSecret: this.apiSecret, privateKey: this.privateKey,
              funderAddress: this.proxyAddress, signatureType: this.signatureType };
}

apiToken never appears anywhere in sdks/typescript/ (confirmed via full-package grep — zero matches). The Metaculus class (client.ts:3564-3568) has no constructor override to add the field, unlike SuiBets (client.ts:3684-3691), which does override getCredentials() to add its own venue-specific field. The class's own JSDoc even claims "authenticated calls accept a bearer token via apiKey" — incorrect, since the server discards apiKey for this venue.

Python SDK

Works correctly — sdks/python/pmxt/client.py:329 (api_token constructor param) and client.py:569-570:

if self.api_token:
    creds["apiToken"] = self.api_token

Evidence

grep -rn "apiToken" sdks/typescript/ returns zero matches anywhere in the TypeScript package. exchange-factory.ts:110-114 reads only credentials?.apiToken for the metaculus case; the TS ExchangeOptions/getCredentials() machinery has no field with that name to populate it.

Impact

Every authenticated Metaculus operation — and per core's own docs, effectively every operation, since Metaculus rejects unauthenticated requests entirely — is unreachable through the TypeScript SDK. new Metaculus({ apiKey: '...' }) silently sends a field the server discards for this venue; the request goes through as anonymous and is rejected by Metaculus. This is distinct from the already-filed passphrase-field gap (#2039, a different field/venue) and from #2136 (a docs-only issue about the self-hosted config table).


Found by automated Core-to-SDK surface coverage audit

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions