https://api.cashsdk.com/mcp is the same server and keeps working. Both
hostnames are one service, so a config written against either survives.
MCP server
Connect any agent to CashSDK with the hosted MCP server at https://mcp.cashsdk.com/mcp: Streamable HTTP, OAuth 2.1 or a bearer token.
The CashSDK Model Context Protocol server is hosted, so there is nothing to install. It's a thin, stateless proxy over the CashSDK REST API: every tool maps to an API call made with the token you send, so an agent can create apps, manage catalog, build paywalls, wire webhooks and read revenue without ever holding your dashboard session.
| URL | https://mcp.cashsdk.com/mcp |
| Transport | Streamable HTTP (remote) |
| Auth | OAuth 2.1, or Authorization: Bearer csk_mcp_… |
| Cost | Free on every plan, including the sandbox |
Choose how to authenticate#
For clients that take a URL and sign you in: Claude on the web and Claude Desktop. Paste the URL, approve in the browser, done.
For clients that send a header: Claude Code, Cursor, Codex, VS Code, Windsurf, Zed, Gemini CLI. Create it in the dashboard.
Get an MCP token#
Dashboard → Settings → MCP → Create token. Copy it immediately; the full value is shown once and stored only as a hash.
- Workspace-wide by default, so an agent can call
list_appsandcreate_appbefore any app exists. - Narrow it to one app if you'd rather it could only touch that one. The
restriction is real. A narrowed token gets
403on a sibling app in the same workspace. - Choose Read only for analytics, diagnostics, and support agents that should
inspect state without changing it. Read-only tokens receive
403for every mutating API call, including calls made through MCP tools. - It does not expire. Revoke it in the dashboard when you're done, and any agent using it stops on its next call.
Any CashSDK token grants API access. Never commit one. If a config file is checked into your repo, put a placeholder there and have each developer supply their own.
Or use the setup token#
The integration prompt in your dashboard still contains a short-lived
csk_st_… setup token, scoped to one app and to provisioning actions only. It's
the zero-friction path for a first-hour onboarding, but it expires in 24 hours
and minting a new one revokes the last, so it is the wrong thing to leave in a
config file. Use an csk_mcp_… token for anything ongoing.
Client configuration#
Header-based clients need the URL and an Authorization header:
{
"mcpServers": {
"cashsdk": {
"url": "https://mcp.cashsdk.com/mcp",
"headers": { "Authorization": "Bearer csk_mcp_..." }
}
}
}
The exact file differs per client. See Claude Code,
Cursor and Codex. For Claude on the web
or Claude Desktop, add a custom connector and paste
https://mcp.cashsdk.com/mcp; you'll be asked to sign in and pick a workspace.
Verify it's connected#
curl -s https://mcp.cashsdk.com/mcp \
-H "Authorization: Bearer csk_mcp_..." \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | head -c 400
A list of tools comes back. Without a valid credential you get 401 with a
WWW-Authenticate header carrying resource_metadata. That pointer is what
tells an OAuth client where to authenticate, and what tells a token client its
token has been revoked or has expired.
What an agent can't do#
Some of the API is refused for every MCP token, at every role, regardless of what the person who created it can do in the dashboard. An agent reads store listings, webhook payloads and READMEs, any of which can try to steer it, so the boundary is drawn in code rather than left to a prompt:
| Refused | Why |
|---|---|
| Billing, partner payouts, revenue-history import | Moves real money, or what you're billed |
| Team members, invitations, SSO, SCIM | Decides who can get in |
| Deleting a workspace, closing an account | Irreversible |
Uploading store credentials (.p8, service-account JSON) | A human step; the raw file shouldn't pass through a model |
| Rotating the ingest token | Silently breaks store notifications until a human repastes the URL |
| Bulk data export | Bulk PII egress |
| Creating another MCP token | Otherwise a narrow token issues itself a wide one |
Within what's left, a token can never exceed the member who created it, and every
call passes the same AccessService and role checks a dashboard session does.
The token's own read/write permission is enforced in addition to those checks.
Every change an agent makes lands in your workspace audit log with
actorType: "agent" (or agent_setup for the onboarding setup token), alongside
the member whose credential it used, so "was that change mine or my agent's?"
has an answer. Reads are not logged, on MCP or anywhere else.
Rate limits#
| Endpoint | Limit |
|---|---|
POST /mcp | 600 requests/min per IP |
POST /oauth/register | 20/hour per IP |
POST /oauth/token | 120/min per IP |
Set well above what a working agent does (a busy setup session bursts dozens of tool calls a minute) so you should never see one. They exist because these endpoints are unauthenticated by construction and would otherwise be free database load.
Tools#
Tools are grouped by what they touch. Each maps directly onto a REST endpoint, so results are the same JSON your backend would receive.
Workspace
| Tool | Description | | --- | --- | | list_apps | Every app in the
workspace. Start here with no app id. | | create_app | Create an app from
a bundle id or Android package name. | | get_app | Fetch an app's
configuration. | | update_app_settings | Change app-level settings. |
Setup & diagnostics
| Tool | Description | | --- | --- | | get_setup_checklist | The live
go-live checklist and what's outstanding. | | get_setup_diagnostics |
Store-side problems, each with its fix. | | get_ios_integration_snippets |
Ready-to-paste iOS integration code. | | get_android_integration_snippets
| The same for Android. |
Catalog
| Tool | Description | | --- | --- | | get_catalog | List products and
entitlements. | | create_product | Create a product (subscription or
one-time). | | create_entitlement | Create an entitlement. | |
grant_entitlement | Grant an entitlement to a customer. | |
sync_catalog_from_app_store | Pull catalog data from the App Store or
Google Play. | | push_catalog_to_app_store | Push your CashSDK catalog to
the store. |
Paywalls, placements & experiments
| Tool | Description | | --- | --- | | list_templates | List available
paywall templates. | | list_paywalls | List existing paywalls. | |
get_paywall | One paywall's config, published and draft. | |
create_paywall | Create a paywall from scratch. | |
create_paywall_from_template | Create a paywall from a template. | |
generate_paywall | Generate a paywall from a natural-language brief (draft
only). | | publish_paywall | Publish the draft so devices receive it. | |
list_placements | List placements. | | create_placement | Create a
placement. | | list_campaigns | List campaigns. | | create_campaign |
Create a campaign, or an A/B split with a holdout. | |
get_experiment_results | Per-variant conversion, revenue and significance.
|
Customers, revenue & keys
| Tool | Description | | --- | --- | | get_customer | Fetch a customer and
their entitlements. | | list_transactions | List transactions. | |
tail_recent_events | The most recent events. | | get_revenue_overview |
Revenue, active subscriptions, trials and churn. | | list_api_keys | Key
ids and masked values, never a raw secret. | | create_api_key | Create a
new API key. | | rotate_api_key | Rotate an existing API key. |
Store notifications & webhooks
| Tool | Description | | --- | --- | | get_store_notification_urls | The
ASSN (Apple) / RTDN (Play) URL to paste into the console. | |
request_apple_test_notification | Ask the store to send a test
notification. | | list_webhook_endpoints | Endpoints registered for an
app. | | register_webhook_endpoint | Register a webhook endpoint URL. | |
send_test_webhook | Send a test event to a webhook endpoint. |
Marketplace
| Tool | Description | | --- | --- | | list_marketplace_apps | Every
connector this workspace can connect. | | list_marketplace_connections |
What's connected, with lifecycle status. | | get_marketplace_status | One
connection in full. | | connect_marketplace_app | Connect a billing
backend or integration. | | start_marketplace_oauth | Begin a “Connect
with X” OAuth flow. | | map_marketplace_catalog | Map a provider's plans
to CashSDK products. | | validate_marketplace_connection | Check
credentials, secret and mappings. | | activate_marketplace_connection |
Start events flowing into the ledger. | | pause_marketplace_connection |
Pause without disconnecting. | | disconnect_marketplace_app | Disconnect
and wipe stored credentials. |
Marketplace writes need an csk_mcp_… token or OAuth. A setup token is
read-only there by design. Connecting a provider installs a billing
credential, which is outside "set up this app's SDK".
OAuth details#
For anyone implementing against it directly:
| Endpoint | |
|---|---|
| Protected-resource metadata | /.well-known/oauth-protected-resource (RFC 9728) |
| Authorization-server metadata | /.well-known/oauth-authorization-server (RFC 8414) |
| Dynamic client registration | POST /oauth/register (RFC 7591) |
| Authorization | GET /oauth/authorize |
| Token | POST /oauth/token |
| Revocation | POST /oauth/revoke (RFC 7009) |
PKCE is required and only S256 is accepted. Access tokens live one hour;
refresh tokens live 30 days and rotate on every use. Redirect URIs are matched
exactly against what the client registered, with a loopback exception for native
clients (RFC 8252 §7.3).