Plans & Subscriptions
Define pricing tiers, let users pick a plan through a hosted page, and gate features using the plan claim in the JWT. No billing code in your app — Astapa stores the plan as a custom claim and your app reads it from the token.
How it works
Define plans in the dashboard or via API — free, pro, team, whatever you need
Hosted plan selection page after login, or assign plans programmatically via API
Selected plan is stored as a plan custom claim in the access token
Your app reads the JWT claims and controls access — no extra API calls needed
Plan structure
Each plan has these fields. Create them in the dashboard (Project → Plans tab) or via the API.
| Field | Description |
|---|---|
| plan_key | Unique slug (e.g. pro). Lowercase, alphanumeric, hyphens, underscores. 1–64 chars. |
| display_name | Human-readable name shown to users (e.g. "Pro Plan") |
| price | Price as a number (e.g. 9.99). Supports decimals. |
| currency | USD or IDR |
| period | monthly, yearly, or one_time |
| description | Optional description (max 512 chars) |
Hosted plan selection
When your project has plans defined, Astapa automatically shows a plan selection page after login — before redirecting to your app. Zero code changes needed.
Assigning plans programmatically
Need to assign plans from your backend? Use the Claims API to set the plan claim — perfect for payment webhooks, admin tools, or onboarding flows.
// After confirming payment, update the user's plan
await fetch("https://astapa.com/api/platform/claims", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
email: "user@example.com",
claims: { plan: "pro" },
}),
});Feature gating with the JWT
After verifying the access token, read the plan claim to determine the user's tier. Your app decides what each plan level unlocks.
import jwt from "jsonwebtoken";
const decoded = jwt.verify(accessToken, publicKey, {
algorithms: ["RS256"],
});
const plan = decoded.plan; // "free" | "pro" | "team" | undefined
if (plan === "pro" || plan === "team") {
// Unlock premium features
} else {
// Free tier or no plan
}Common subscription patterns
Plans are stored as custom claims, so you can model various patterns beyond simple tiers:
| Claim | Value | Use case |
|---|---|---|
| plan | "pro" | Feature gating by tier |
| trial_ends | "2026-04-15" | Time-limited trial access |
| feature_flags | "beta,export" | Granular feature toggles |
| seats | "10" | Seat-based licensing |
API reference
Plan CRUD (dashboard)
Plan CRUD (server-to-server)
Manage plans from your backend using client credentials.