Appearance
Packages: Create and Manage Plans
Overview
A package is a plan. It answers three questions at once for every company assigned to it:
- What does it cost? — monthly and yearly price.
- How much may they use? — API requests, tokens, users, documents, storage, API keys.
- What may they do? — the capability flags (
features) that switch product areas on and off, such as PII sanitization, SSO, Cost Intelligence or structured document parsing.
A subscription (CompanyPackage) is the link between one company and one package for a billing period. Packages are the catalogue; subscriptions are who bought what.
| Concept | What it holds | Where you manage it |
|---|---|---|
| Package | Price, limits, capabilities | Admin → Packages → Packages tab |
| Subscription | Company, package, billing period, amount, period usage counters | Admin → Packages → Subscriptions tab |
Access and permissions
| Action | Required role |
|---|---|
| View, create, edit, delete packages | SUPER_ADMIN |
| Assign or change a company's subscription | SUPER_ADMIN |
| View the resulting billing figures | SUPER_ADMIN, ACCOUNTANT |
Every create, update and delete is written to the audit log with the acting user, the package and the changed values.
Creating a package
UI path: /admin/packages → Packages tab → New package
1. Identity
| Field | Notes |
|---|---|
| Name | Must be unique across the platform. Attempting to reuse a name returns 409. This is the label customers see, so name it commercially ("Team", "Enterprise"), not internally ("tier-3-v2"). |
| Description | One line explaining who the plan is for. Shown on the plan-selection screens. |
| Account type | INDIVIDUAL (single user), TEAM (2-10 users), ENTERPRISE (10+). Drives default framing and some product copy. |
2. Price
| Field | Notes |
|---|---|
| Price per month | The list price. Leave at 0 for an internal, trial or partner package. |
| Price per year | The annual price, if you sell one. Set it to the discounted annual total, not twelve times the monthly figure. |
Prices are held in the platform's billing currency (USD). A company's lead currency (baseCurrency, USD or EUR) affects how figures are displayed to that company and in accounting reports; it does not convert what is charged. See Accounting.
3. Limits
| Field | Effect when exceeded |
|---|---|
| API requests per month | Gateway calls are refused once the period allowance is used. |
| API tokens per month | Token allowance for the period. Leave empty for no token cap. |
| Max users | Blocks further invitations. |
| Max documents / Max document size | Blocks upload. |
| Response storage (GB) / Max response count | Bounds retained gateway responses. |
| Max Gateway API keys | Caps active keys per company. Defaults to 10. |
Leave a numeric limit empty to mean unlimited. Setting it to 0 means none — those are very different, and 0 is the one that will generate support tickets.
4. Capabilities (features)
Capabilities are boolean and numeric flags stored as JSON on the package. The important ones:
| Key | Unlocks |
|---|---|
allowPiiSanitization | Shield PII detection and tokenization |
allowVeritas (+ maxVeritas*) | Veritas document hardening, with its own per-month and per-job caps |
allowTextHygiene | The Shield "Clean Text" tool |
allowGeoFencing | Configuring geo-fencing rules on projects and prompts |
allowSso | Enterprise SSO connectors, domain verification, SCIM |
allowCostIntelligence | The Sherlock cost module |
allowOpsAnalytics, allowAuditQueries, allowDataResearch, allowQualityAnalytics, allowSecurityAnalytics, allowRoutingAnalytics | The individual analytics add-ons |
allowArchitect | Project Architect |
allowMcpTools, allowWebhooks, allowExport, allowTeamCollaboration, allowGuruChat | The corresponding product areas |
allowStructuredDocumentParsing (+ maxDocumentParsePages) | Layout-aware PDF parsing rather than plain text extraction |
promptProtection | Protective prompt wrapping at the gateway |
displayFeatures | A list of strings shown on pricing screens — marketing copy, not a gate |
Two rules worth internalising before you edit a feature flag:
- Most gates fail closed. A capability that is absent is denied, not granted. This is deliberate: a package created without a flag must lose capability, never gain it.
- Selling a tool is not the same as selling whether a policy is honoured.
allowGeoFencingandallowTextHygienegate the configuration tools. Rules a company has already configured — a geo-fence, a Unicode-hygiene block — keep being enforced at the gateway even on a plan that no longer includes the tool. A compliance control must not silently stop applying because of a billing state.
5. Flags
| Flag | Meaning |
|---|---|
| Active | Inactive packages cannot be newly assigned; existing subscriptions keep running. |
| Default | The package new signups land on. Exactly one package should carry this. |
| BYOK required | Companies on this package must supply their own provider API keys. |
6. Stripe linkage (optional)
Stripe product ID, Stripe price (monthly) and Stripe price (yearly) connect the package to Stripe so self-serve checkout and the customer portal work. Leave them empty for packages you invoice manually — the package still functions, it simply has no self-serve path.
Editing a package
UI path: /admin/packages → Packages tab → the package → Edit
Changes apply to every company already on the package, immediately, including any mid-period company. Before saving:
- Lowering a limit can put existing companies instantly over quota. Check who is on the package first, using the Subscriptions tab.
- Removing a capability takes the feature away at the next request. Where a downgrade would break a running configuration, the platform shows a downgrade notice on the customer's billing page — but you should still tell them.
- Raising a price does not re-invoice anyone retroactively. It applies from the next billing period.
Deleting a package
UI path: /admin/packages → Packages tab → the package → Delete
Deletion is protective:
- If no company has ever subscribed, the package is deleted outright.
- If any subscription exists, the package is deactivated instead of deleted, and the response says how many subscriptions kept it alive. Historical subscriptions and the invoices derived from them stay intact — which is exactly what you want, because deleting a package under a past invoice would orphan the line item that explains the charge.
Assigning a package to a company
UI path: /admin/packages → Subscriptions tab → Assign subscription
Choose the company, the package, the billing period (MONTHLY or YEARLY) and the amount. The amount is deliberately editable and separate from the package's list price — that is how you record a negotiated price without creating a bespoke package for every customer.
The subscription then tracks, for the current period: usedApiRequests, usedApiTokens, usedInputTokens, usedOutputTokens, nextBillingDate, and — for Stripe-backed subscriptions — stripeSubscriptionStatus, currentPeriodStart/End and cancelAtPeriodEnd.
Changing a company's package
Assign the new package on the Subscriptions tab. Then check three things:
- Usage counters. They belong to the subscription period, not to the company. Confirm the figures on
/accountantlook right for the period you are about to invoice. - Capability loss. Compare the two packages'
features. Anything the new package does not grant stops working. - Provider bundles. If the packages have different provider bundles, re-run the bundle sync for the package (
/admin/package-provider-bundles) so routing sees the right provider set.
Related settings
| Setting | Where | What it does |
|---|---|---|
| Package limits | /admin/package-limits | Fine-grained limit overrides |
| Provider bundles | /admin/package-provider-bundles | Which providers a package may route to |
| Promo codes | /admin/promo-codes | Discounts and bonus allowances, optionally targeted at one package |
| Payment status | /admin/payment-management | Grace periods and suspension, independent of the package |
| Bulk move companies to the free package | /accountant/customers → Import Actions | A platform accountant/SUPER_ADMIN can bulk-apply DOWNGRADE_TO_FREE from a CSV of unpaid companies — see Accounting: bulk unpaid-action import |
API reference
bash
# List packages
curl -s https://app.veriprompt.tech/api/admin/packages \
-H "Cookie: <admin session>"bash
# Create a package
curl -s -X POST https://app.veriprompt.tech/api/admin/packages \
-H "Content-Type: application/json" \
-H "Cookie: <admin session>" \
-d '{
"name": "Team",
"description": "For teams of 2-10 building on the gateway",
"accountType": "TEAM",
"pricePerMonth": 149,
"pricePerYear": 1490,
"apiRequestsPerMonth": 250000,
"apiTokensPerMonth": 20000000,
"maxUsers": 10,
"maxApiKeys": 25,
"isActive": true,
"features": {
"allowPiiSanitization": true,
"allowMcpTools": true,
"allowExport": true,
"maxProjects": 25
}
}'PUT /api/admin/packages updates (body carries id); DELETE /api/admin/packages?id=<id> deletes or deactivates as described above.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
409 A package with this name already exists | Names are unique platform-wide, including inactive packages | Rename, or reactivate the existing package |
| A customer reports a feature "disappeared" after a plan change | The new package's features omits the flag; absent means denied | Add the flag to the package, or move the company back |
| Delete returned "Package deactivated" instead of deleting | Subscriptions reference it | Expected. Reassign those companies first if you truly need the row gone |
| A limit change did not take effect | Gateway context is cached per company | Package deletion invalidates gateway contexts automatically; for edits, allow the cache to turn over or reassign the subscription |
| Feature is on in the package but still denied | The gate may read the company's merged features, and a seeding path can set features on create but not on update | Re-save the package; the npm run test:seed-parity guard exists specifically for this drift |
