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-mcp

Create 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:

ReasonMeaning
no_license_keyNo key provided
invalid_key_formatKey doesn't match VEND-XXXX-XXXX-XXXX-XXXX
invalid_api_keyYour project API key is wrong
key_not_foundKey doesn't exist or belong to your project
key_inactive / key_expired / key_revokedKey is no longer valid
network_errorCould 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

Tiers

Tiers are ordered. A pro key can access free and starter tools.

TierLevel
free0
starter1
pro2
business3
enterprise4

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

EventFired When
key.createdA new license key is created via checkout
key.activatedA key is activated for an MCP client instance
key.deactivatedA key is deactivated due to payment failure
key.reactivatedA key is reactivated after payment recovery
subscription.cancelledA subscription is cancelled
usage.limit_reachedA key hits its tier request limit
rate_limit_exceededA key hits its per-minute rate limit
tool_not_allowedA request invokes a tool not in the key’s tier gate
upstream_blockedThe proxy rejected the upstream URL (SSRF / DNS)
proxy.quota_warningKey has consumed 80% of its monthly request quota
proxy.quota_reachedKey has consumed 100% of its monthly request quota
webhook.secret_rotatedThe 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

VariableDescription
VEND_LICENSE_KEYCustomer's license key (set by the end user)
VEND_API_URLOverride the API URL (default: https://vend.sh)

Questions? Reach out at support@vend.sh.