DEVELOPERS · PLUGIN PLATFORM
Extend OnGravy with plugins
OnGravy's plugin platform is the modern successor to Tally's TDL: a declarative manifest, a closed permission set, and a sandboxed runtime that audits every call. Ship voucher hooks, custom reports, dashboard widgets, exports, and webhooks without forking the codebase.
Plugin marketplace launches Q2 2027. Today plugins are invite-only review — email plugins@ongravy.com with your manifest and we'll get you into the early-access cohort.
How a plugin works
- 1ManifestA plain object — id, version, name, author, description, category, entrypoint, permissions, optional jurisdictions. This is the trust boundary. Whatever the manifest doesn't declare, the runtime literally won't let you call.
- 2RegistryEach plugin module calls registerPlugin(manifest, factory) at import time. The registry validates the id (regex), the version (SemVer), and every permission (closed set). Bad manifests fail fast at boot, not at runtime.
- 3SandboxOn invocation, the runtime builds a context object that contains only the methods your manifest requested. Asked for read:vouchers but not write:vouchers? ctx.writeVoucherTags is undefined. There's no monkey-patching around this.
- 4Audit trailEvery invocation — success, denial, or error — appends one event to activity_events with the plugin id, version, caller user/business, jurisdiction, outcome, and duration. Admins can revoke a plugin's permissions with a single click and watch the audit log confirm it.
A worked example
Reproduced verbatim from plugins/sample-voucher-tagger/index.ts. This plugin auto-applies a high-value tag to every voucher of ₹50,000 or more.
import { registerPlugin } from '@/lib/plugins/registry';
import type { PluginManifest } from '@/lib/plugins/types';
const HIGH_VALUE_THRESHOLD_PAISE = 50_000 * 100; // 50_00_000
const manifest: PluginManifest = {
id: 'sample-voucher-tagger',
version: '1.0.0',
name: 'High-Value Voucher Tagger',
author: 'OnGravy',
description: 'Auto-applies the "high-value" tag to vouchers worth ₹50K or more.',
category: 'voucher',
entrypoint: 'plugins/sample-voucher-tagger/index.ts',
permissions: ['read:vouchers', 'write:vouchers'],
};
registerPlugin(manifest, () => async (ctx) => {
if (!ctx.readVouchers || !ctx.writeVoucherTags) {
return { ok: false, error: 'missing required permissions' };
}
const candidates = await ctx.readVouchers({
minAmountPaise: HIGH_VALUE_THRESHOLD_PAISE,
});
const tagged: string[] = [];
for (const v of candidates) {
if (v.tags.includes('high-value')) continue;
await ctx.writeVoucherTags(v.id, [...v.tags, 'high-value']);
tagged.push(v.id);
}
return { ok: true, data: { taggedCount: tagged.length, tagged } };
});Permission matrix
The complete, current set. 9 permissions in API v1. Adding a new permission is a host change — plugins cannot extend the set on their own.
| Permission | Capability | Risk |
|---|---|---|
read:vouchers | List vouchers + filters (type, amount range). | low |
write:vouchers | Append cost-centre tags to a voucher. | medium |
read:parties | Read the customer/supplier ledger. | low |
write:parties | Create or update party records. | medium |
read:items | Read the inventory item master. | low |
write:items | Create or update item-master records. | medium |
read:reports | Pull canned reports (P&L, BS, GST) read-only. | low |
send:webhook | POST to an outbound URL with a JSON payload. | high |
render:dashboard-widget | Render a tile on the home dashboard. | low |
Submit a plugin for review
Send us your manifest and source. We'll review for security and behaviour, then load it for your business inside one week.
Email plugins@ongravy.comFAQ
How do I distribute a plugin?
Today: send the source + manifest to plugins@ongravy.com. We review for security and behaviour, then load it as a first-party module. The Q2 2027 marketplace will let CAs and ISVs upload directly.
What does the review process look like?
We check the manifest (permissions match behaviour), read the entrypoint for unsafe patterns, run our sandbox harness, and pilot the plugin on a sandbox business for one week. Most reviews close in 5 business days.
What can I charge for a plugin?
Anything. Today commercials are bilateral — you set the price, we collect via OnGravy billing and take a 15% platform fee. The marketplace will introduce a self-serve pricing surface.
How does the lifecycle work?
Plugins are versioned (SemVer). A new version is reviewed before it goes live. Businesses can pin to a specific version; admins see a "1 update available" badge in the plugin manager.
Can plugins make my data leave OnGravy?
Only if you grant send:webhook. Every outbound call is logged to your audit trail with the URL, payload shape, and timestamp. Admins can revoke send:webhook at any time without uninstalling the plugin.
What languages can I write plugins in?
TypeScript today. The entrypoint is an async function that receives a sandbox context. A WASM runtime is on the roadmap for sandboxed third-party code.
Can a plugin block a voucher from saving?
Not yet — write:vouchers only appends tags. A blocking validator surface (with side_effect:block_save semantics) ships in plugin API v2, mid-2026.