import { createApiKeySdk } from "keystash-sdk"; const sdk = createApiKeySdk({ baseUrl: "https://api.keystash.dev" }); await sdk.account.connect(import.meta.env.VITE_KEYSTASH_PUBLISHABLE_KEYUse a publishable app key here, not an admin key. Scope it to one space, one origin, and specific feature ids.); const session = await sdk.runtime.sessions.create({ spaceId: "acme-prod", endUserId: auth.user.idUse the same stable SaaS user id in frontend runtime calls and in Stripe metadata or client_reference_id. No separate create-user step is required., operationIds: ["op_live_abc123"Feature id returned by the control plane. Scope the publishable key to the same id.], ttlMinutes: 15Keystash returns a short-lived runtime token instead of provider credentials. }); await sdk.runtime.connect(session.tokenResult:kst_rt_...scoped toacme-prod, one user id, one feature id, and a 15 minute TTL.);
const billing = await sdk.spaces.endUserBilling.update("acme-prod", {
stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!Keystash verifies Stripe signatures before granting spend.,
endUserIdSource: "metadata",
endUserIdMetadataKey: "keystash_end_user_id"Stripe checkout metadata field that tells Keystash which SaaS user to fund.,
spendAmountSource: "metadata",
spendAmountMetadataKey: "keystash_spend_usd"Stripe metadata field that defines how much runtime spend to grant.
});
console.log(billing.webhookUrlResult: https://api.keystash.dev/api/spaces/acme-prod/end-user-billing/stripe/webhook);
{
type: "checkout.session.completed"Keystash handles the completed payment once per Stripe event id.,
data: {
object: {
metadata: {
"keystash_end_user_id": "user_123"Match the same user id you pass when minting browser runtime sessions.,
"keystash_spend_usd": "25"Result: Keystash creates or tops up that user's spend record with $25.
}
}
}
}
const result = await sdk.runtime.invoke({ operationId: "op_live_abc123"Use the same feature id that the publishable key and runtime session were scoped to., input: { ticket: "Customer asks for refund after duplicate charge." } }, session.token); const summary = result.outputTextResult:"Duplicate charge. Refund likely. Escalate billing."; const billedTokens = result.usage.totalTokensResult:248tokens. Usage is tracked against that user and deducted from remaining spend.; const model = result.modelResult:openai/gpt-5.4-minias configured in the hidden feature.;
const feature = await sdk.spaces.operations.create("acme-prod", {
title: "Summarize ticket",
slug: "summarize_ticket",
model: "openai/gpt-5.4-mini",
systemPrompt: "You summarize support tickets for internal agents.",
userTemplate: "Ticket:\n{{ticket}}\n\nReturn a concise summary.",
monthlyInvocationLimit: 10000,
allowedOrigins: ["https://app.acme.com"]
});