Documentation
Everything you need to integrate Vend into your MCP server. Install the SDK, gate tools by tier, track usage, and get paid.
Getting Started
Install the SDK:
npm install @yawlabs/vend-mcpCreate a project at vend.sh, grab your API key from the dashboard, and add it to your server:
import { vendAuth } from '@yawlabs/vend-mcp';
const guard = vendAuth({
apiKey: process.env.VEND_API_KEY!,
gates: {
search: 'free',
execute: 'pro',
deploy: 'business',
},
});Customers purchase a license key at your checkout page, set VEND_LICENSE_KEY in their MCP client config, and the SDK handles validation, caching, and gating.
SDK Reference
vendAuth(options): VendGuard
Creates a guard instance. Validation is lazy — no API calls until the first canAccess() or validate().
const guard = vendAuth({
// Required
apiKey: 'vend_xxx', // Project API key from dashboard
gates: { search: 'free', run: 'pro' }, // Tool name → minimum tier
// Optional
licenseKey: 'VEND-XXXX-...', // Override (default: process.env.VEND_LICENSE_KEY)
cacheTtl: 300, // Cache successful validations (seconds, default: 300)
errorCacheTtl: 30, // Cache failed validations (seconds, default: 30)
// Observability hooks (all optional)
onValidate: (result, fromCache) => {},
onActivate: (result) => {},
onUsage: (toolName, success) => {},
onError: (operation, error) => {},
});guard.canAccess(toolName): Promise<boolean>
Check if the current key can access a tool. Calls validate() internally (cached).
if (!(await guard.canAccess('deploy'))) {
return {
content: [{ type: 'text', text: guard.upgradeMessage('deploy') }],
};
}guard.validate(): Promise<ValidationResult>
Validate the license key against the Vend API. Results are cached.
const result = await guard.validate();
// {
// valid: true,
// tier: 'pro',
// tierName: 'Pro',
// toolGates: { search: true, execute: true },
// requestLimit: 10000,
// activationsRemaining: 4,
// }Failure reasons:
| Reason | Meaning |
|---|---|
| no_license_key | No key provided |
| invalid_key_format | Key doesn't match VEND-XXXX-XXXX-XXXX-XXXX |
| invalid_api_key | Your project API key is wrong |
| key_not_found | Key doesn't exist or belong to your project |
| key_inactive / key_expired / key_revoked | Key is no longer valid |
| network_error | Could not reach vend.sh (falls back to cache) |
guard.recordUsage(toolName): Promise<boolean>
Record a tool invocation. Safe to fire-and-forget:
// Fire-and-forget
guard.recordUsage('search');
// Or await for confirmation
const ok = await guard.recordUsage('search');guard.activate(instanceName, instanceId): Promise<ActivationResult>
Activate the key for a specific MCP client instance. Call once on startup:
const result = await guard.activate('claude-desktop', crypto.randomUUID());
if (!result.activated) {
console.error(`Activation failed: ${result.reason}`);
}createToolGuard(guard)
Auto-gate and track usage for an MCP CallToolRequest handler:
import { vendAuth, createToolGuard } from '@yawlabs/vend-mcp';
const guard = vendAuth({
apiKey: '...',
gates: { search: 'free', run: 'pro' },
});
const gated = createToolGuard(guard);
server.setRequestHandler(
CallToolRequestSchema,
gated(async (request) => {
// Only runs if the key has access
// Usage is recorded automatically on success
return { content: [{ type: 'text', text: 'result' }] };
}),
);Other Properties
guard.tier— the current customer's tier after validation (free,starter,pro,business,enterprise)guard.upgradeMessage(toolName)— human-readable upgrade promptguard.licenseKey = 'VEND-...'— update the key at runtime (clears cache)
Tiers
Tiers are ordered. A pro key can access free and starter tools.
| Tier | Level |
|---|---|
| free | 0 |
| starter | 1 |
| pro | 2 |
| business | 3 |
| enterprise | 4 |
API Endpoints
All endpoints require the x-vend-api-key header with your project API key. Base URL: https://vend.sh
POST /api/v1/keys/validate
Validate a license key. Target: < 50ms response time.
// Request
{ "key": "VEND-XXXX-XXXX-XXXX-XXXX" }
// Response (valid)
{
"valid": true,
"tier": "pro",
"tierName": "Pro",
"toolGates": { "search": true, "execute": true },
"requestLimit": 10000,
"activationsRemaining": 4,
"_meta": { "ms": 12 }
}
// Response (invalid)
{ "valid": false, "reason": "key_expired", "tier": "pro" }POST /api/v1/keys/activate
Activate a key for a specific client instance.
// Request
{
"key": "VEND-XXXX-XXXX-XXXX-XXXX",
"instance_name": "claude-desktop",
"instance_id": "abc-123"
}
// Response
{ "activated": true, "instanceId": "uuid" }POST /api/v1/usage
Record tool invocations. Enforces request limits and tool gates.
// Request
{
"license_key": "VEND-XXXX-XXXX-XXXX-XXXX",
"tool_name": "search",
"count": 1,
"metadata": { "query": "example" }
}
// Response
{ "recorded": true }
// 429 when limit exceeded
{ "error": "request_limit_exceeded", "limit": 10000, "used": 10000 }
// 403 when tool is gated
{ "error": "tool_not_allowed", "tool": "search" }Webhooks
Configure a webhook URL in your project settings to receive real-time events. Events are signed with HMAC-SHA256 using your webhook secret, sent in the x-vend-signature header.
Events are retried up to 3 times with exponential backoff on failure.
Event Types
| Event | Fired When |
|---|---|
| key.created | A new license key is created via checkout |
| key.activated | A key is activated for an MCP client instance |
| key.deactivated | A key is deactivated due to payment failure |
| key.reactivated | A key is reactivated after payment recovery |
| subscription.cancelled | A subscription is cancelled |
| usage.limit_reached | A key hits its tier request limit |
| rate_limit_exceeded | A key hits its per-minute rate limit |
| tool_not_allowed | A request invokes a tool not in the key’s tier gate |
| upstream_blocked | The proxy rejected the upstream URL (SSRF / DNS) |
| proxy.quota_warning | Key has consumed 80% of its monthly request quota |
| proxy.quota_reached | Key has consumed 100% of its monthly request quota |
| webhook.secret_rotated | The webhook secret was rotated (signed with the OLD secret — verify, then switch) |
Payload Format
{
"id": "uuid",
"type": "key.created",
"data": { "key_id": "uuid", "customer_email": "...", "tier_id": "uuid" },
"timestamp": "2026-04-09T00:00:00.000Z"
}Verifying Signatures
import { createHmac } from 'crypto';
function verify(body: string, signature: string, secret: string) {
const expected = createHmac('sha256', secret).update(body).digest('hex');
return signature === expected;
}Rate Limits
All /api/v1/* endpoints are rate-limited to 50 requests per minute per API key. Exceeding the limit returns 429 with a Retry-After header.
Environment Variables
| Variable | Description |
|---|---|
| VEND_LICENSE_KEY | Customer's license key (set by the end user) |
| VEND_API_URL | Override the API URL (default: https://vend.sh) |
Questions? Reach out at support@vend.sh.