Manage discount codes with API and MCP
Create shareable pilot offers and inspect or deactivate them as a site administrator.
Site administrators can create, list, inspect, edit, and deactivate reusable subscription discount codes through REST or MCP. The same validation and audit records apply as in Site Admin → Discounts.
OAuth MCP calls use your signed-in site-admin identity. A paired local gateway uses its owner's identity. For REST or API-key MCP, create a key in Settings → API Keys with Manage discount codes across Pencil enabled. Only site admins can grant this permission; existing keys do not inherit it. Read keys can inspect offers; write keys can create and deactivate them. MCP keys also need MCP access enabled. Revoking the key or removing its creator's site-admin or organization-admin access stops discount management.
The MCP tools are list_discount_codes, get_discount_code, create_discount_code, update_discount_code, and deactivate_discount_code. Use the code itself when inspecting or deactivating an offer. List returns at most 100 offers per page and a nextCursor. Get includes the 100 most recent redemptions and the ten most recent audit events.
Create an offer with code, label, percentOff, duration (once, repeating, or forever), and planKey (pro or team). For repeating, provide months (1–36). maxRedemptions accepts 1–10,000, or null for unlimited; omission preserves the single-use default. Optional redeemFrom and redeemBy values are Unix timestamps in milliseconds that bound when a new redemption may begin. Omit both recipient fields for a shareable code. Supplying targetUserId or targetOrgId restricts the offer and requires exactly one redemption.
For a 50% Pro monthly discount lasting 12 months:
{"code":"OCTOBER50","label":"October offer","percentOff":50,"duration":"repeating","months":12,"planKey":"pro","maxRedemptions":null,"redeemFrom":1792123200000,"redeemBy":1793505600000}
REST uses GET /api/v1/discount-codes, POST /api/v1/discount-codes, GET /api/v1/discount-codes/{code}, PATCH /api/v1/discount-codes/{code}, and POST /api/v1/discount-codes/{code}/deactivate. Authenticate with a bearer API key. Responses use the usual {data} envelope; consult the OpenAPI reference for the complete contract.
Creation returns the normalized code. Share https://app.pencil.ink/sign-up?discountCode=CODE with recipients. Each organization can claim a reusable code only once, and every reservation counts against a finite limit until an unused operation is reconciled. Discounts cover eligible USD monthly base subscriptions; AI usage is separate. Creation does not enable the global redemption switch or perform a Stripe operation. Verify enabled from the list response and billing rollout readiness before promising redemption.
Before redemption starts, choose Edit code in Site Admin → Discounts to change the label, percentage, plan, duration/months, redemption limit, or active window. The same code and signup link remain valid. The code text and recipient cannot be changed. Save records before/after terms in the audit history.
To change an ongoing offer to twelve months, call update_discount_code with {"code":"PILOT50","duration":"repeating","months":12}, or PATCH its REST resource with {"duration":"repeating","months":12}. Omitted fields are preserved; redeemFrom: null and redeemBy: null clear their respective boundaries, while maxRedemptions: null makes an untargeted code unlimited. Identical updates do not add duplicate audit events.
Any redemption history (pending, applied, removed, or abandoned) locks terms. This prevents a concurrent checkout from applying stale Stripe coupon terms. Changing an already-claimed offer requires a new code; editing does not modify existing Stripe subscriptions. Deactivation preserves already-applied discounts and refuses pending redemptions until their Stripe sessions are reconciled. Repeated deactivation is safe. Creation rejects duplicate codes: after an uncertain response, inspect the code before retrying; never automatically generate a different code.