Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, email [email protected] and we’ll put it right.

VHGENGINE

REMOTE · ENGINE-PRODUCTION-3BDC.UP.RAILWAY.APP · SCANNED AUG 3

Agents-first viral-hook engine: generate, score, and remix short-form hooks over MCP.

+13 this week 65 Trust /100
Trust breakdown (6 categories)

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. How we score →

Endpoint Security63
Transport & Reachability100
Schema Quality & AI Usability53
  • 43% of prompts and resources have a non-trivial description (not blank, and not just the item's name).Partial
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 14279 tokens (~274/item across 52 items; 38 tools + 14 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management27
  • Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 100% of tool parameters carry a description.Pass
  • Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Capabilities100
  • Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Install

Add this component to your MCP client. Where a client-specific snippet is available, pick your client below and copy it straight into your config; otherwise use the connection detail shown.

remote · engine-production-3bdc.up.railway.app

# add to Claude Code
claude mcp add --transport http app-railway-up-engine-production-3bdc-vhgengine https://engine-production-3bdc.up.railway.app/mcp
# ~/.codex/config.toml
[mcp_servers.app-railway-up-engine-production-3bdc-vhgengine]
url = "https://engine-production-3bdc.up.railway.app/mcp"
// opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "app-railway-up-engine-production-3bdc-vhgengine": {
      "type": "remote",
      "url": "https://engine-production-3bdc.up.railway.app/mcp",
      "enabled": true
    }
  }
}
# add to OpenClaw
openclaw mcp add app-railway-up-engine-production-3bdc-vhgengine --url https://engine-production-3bdc.up.railway.app/mcp --transport streamable-http
# ~/.hermes/config.yaml
mcp_servers:
  app-railway-up-engine-production-3bdc-vhgengine:
    url: "https://engine-production-3bdc.up.railway.app/mcp"
// mcp.json
{
  "mcpServers": {
    "app-railway-up-engine-production-3bdc-vhgengine": {
      "type": "http",
      "url": "https://engine-production-3bdc.up.railway.app/mcp"
    }
  }
}

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 3 Aug 26 +6
    • The server rewrote its instructions, which are the text every model session reads security
    • New tool “cancel_job”, which the server declares destructive security
    • Tool “delete_account” rewrote its description, which is the text the model reads security
    • Tool “generate_hooks” rewrote its description, which is the text the model reads security
    • Tool “generate_hooks_batch” rewrote its description, which is the text the model reads security
    • Tool “get_account” rewrote its description, which is the text the model reads security
    • Tool “get_usage” rewrote its description, which is the text the model reads security
    • Tool “health” rewrote its description, which is the text the model reads security
    • Tool “list_hooks” rewrote its description, which is the text the model reads security
    • Tool “remix_hook” rewrote its description, which is the text the model reads security
    • Tool “score_hook” rewrote its description, which is the text the model reads security
    • Tool “signup” rewrote its description, which is the text the model reads security
    • Tool “start_generate_job” rewrote its description, which is the text the model reads security
    • Schema quality: 138 → 274 functional
    • Schema quality: 0% → 43% functional
    • Tool coverage: 0% → 100% functional
    • Schema quality: good → excellent functional
    • New resource “client-guide-claude-desktop” functional
    • New resource “client-guide-codex” functional
    • New resource “client-guide-cursor” functional
    • New resource “client-guide-rest” functional
    • New resource “sample” functional
    • New resource “client-guide-chatgpt” functional
    • New resource “client-guide-claude-code” functional
    • New tool “quote” functional
    • New tool “export_usage” functional
    • New tool “list_billing_events” functional
    • New tool “list_runs” functional
    • New tool “wait_for_job” functional
    • “get_usage” added an optional parameter “offset” cosmetic
    • “remix_hook” added an optional parameter “archetype” cosmetic
    • “remix_hook” added an optional parameter “hook_id” cosmetic
    • “remix_hook” added an optional parameter “platform” cosmetic
    • “remix_hook” added an optional parameter “topic” cosmetic
    • “score_hook” added an optional parameter “topic” cosmetic
    • “score_hooks_batch” added an optional parameter “topic” cosmetic
    • “add_credits” reworded the description of “admin_key” cosmetic
    • “add_credits” reworded the description of “amount” cosmetic
    • “add_credits” reworded the description of “api_key” cosmetic
    • “add_credits” reworded the description of “idempotency_key” cosmetic
    • “create_checkout” reworded the description of “api_key” cosmetic
    • “create_checkout” reworded the description of “cancel_url” cosmetic
    • “create_checkout” reworded the description of “pack” cosmetic
    • “create_checkout” reworded the description of “success_url” cosmetic
    • “create_key” reworded the description of “api_key” cosmetic
    • “create_key” reworded the description of “daily_credit_cap” cosmetic
    • “create_key” reworded the description of “name” cosmetic
    • “create_key” reworded the description of “scopes” cosmetic
    • “delete_account” reworded the description of “api_key” cosmetic
    • “delete_account” reworded the description of “confirm” cosmetic
    • “delete_webhook” reworded the description of “api_key” cosmetic
    • “generate_hooks” reworded the description of “api_key” cosmetic
    • “generate_hooks” reworded the description of “archetypes” cosmetic
    • “generate_hooks” reworded the description of “count” cosmetic
    • “generate_hooks” reworded the description of “deadline_ms” cosmetic
    • “generate_hooks” reworded the description of “idempotency_key” cosmetic
    • “generate_hooks” reworded the description of “mode” cosmetic
    • “generate_hooks” reworded the description of “platform” cosmetic
    • “generate_hooks” reworded the description of “style” cosmetic
    • “generate_hooks” reworded the description of “tags” cosmetic
    • “generate_hooks” reworded the description of “topic” cosmetic
    • “generate_hooks” reworded the description of “verbosity” cosmetic
    • “generate_hooks_batch” reworded the description of “api_key” cosmetic
    • “generate_hooks_batch” reworded the description of “idempotency_key” cosmetic
    • “generate_hooks_batch” reworded the description of “mode” cosmetic
    • “generate_hooks_batch” reworded the description of “platform” cosmetic
    • “generate_hooks_batch” reworded the description of “requests” cosmetic
    • “generate_hooks_batch” reworded the description of “tags” cosmetic
    • “generate_hooks_batch” reworded the description of “verbosity” cosmetic
    • “get_account” reworded the description of “api_key” cosmetic
    • “get_activity” reworded the description of “api_key” cosmetic
    • “get_activity” reworded the description of “recent_limit” cosmetic
    • “get_hook” reworded the description of “api_key” cosmetic
    • “get_hook” reworded the description of “hook_id” cosmetic
    • “get_job” reworded the description of “api_key” cosmetic
    • “get_job” reworded the description of “job_id” cosmetic
    • “get_usage” reworded the description of “api_key” cosmetic
    • “get_usage” reworded the description of “key_prefix” cosmetic
    • “get_usage” reworded the description of “recent_limit” cosmetic
    • “get_usage” reworded the description of “request_id” cosmetic
    • “get_usage” reworded the description of “tag” cosmetic
    • “get_webhook” reworded the description of “api_key” cosmetic
    • “list_hooks” reworded the description of “api_key” cosmetic
    • “list_hooks” reworded the description of “limit” cosmetic
    • “list_hooks” reworded the description of “mode” cosmetic
    • “list_hooks” reworded the description of “offset” cosmetic
    • “list_hooks” reworded the description of “since” cosmetic
    • “list_hooks” reworded the description of “tag” cosmetic
    • “list_hooks” reworded the description of “topic” cosmetic
    • “list_hooks” reworded the description of “unreported” cosmetic
    • “list_jobs” reworded the description of “api_key” cosmetic
    • “list_jobs” reworded the description of “limit” cosmetic
    • “list_jobs” reworded the description of “offset” cosmetic
    • “list_keys” reworded the description of “api_key” cosmetic
    • “list_outcomes” reworded the description of “api_key” cosmetic
    • “list_outcomes” reworded the description of “hook_id” cosmetic
    • “list_outcomes” reworded the description of “limit” cosmetic
    • “list_outcomes” reworded the description of “offset” cosmetic
    • “list_outcomes” reworded the description of “platform” cosmetic
    • “list_outcomes” reworded the description of “since” cosmetic
    • “list_webhook_deliveries” reworded the description of “api_key” cosmetic
    • “list_webhook_deliveries” reworded the description of “limit” cosmetic
    • “list_webhook_deliveries” reworded the description of “offset” cosmetic
    • “list_webhook_deliveries” reworded the description of “status” cosmetic
    • “redrive_webhook_delivery” reworded the description of “api_key” cosmetic
    • “redrive_webhook_delivery” reworded the description of “delivery_id” cosmetic
    • “remix_hook” reworded the description of “api_key” cosmetic
    • “remix_hook” reworded the description of “count” cosmetic
    • “remix_hook” reworded the description of “idempotency_key” cosmetic
    • “remix_hook” reworded the description of “tags” cosmetic
    • “remix_hook” reworded the description of “target_archetype” cosmetic
    • “remix_hook” reworded the description of “text” cosmetic
    • “remix_hook” reworded the description of “verbosity” cosmetic
    • “report_outcome” reworded the description of “api_key” cosmetic
    • “report_outcome” reworded the description of “hook_id” cosmetic
    • “report_outcome” reworded the description of “idempotency_key” cosmetic
    • “report_outcome” reworded the description of “likes” cosmetic
    • “report_outcome” reworded the description of “platform” cosmetic
    • “report_outcome” reworded the description of “posted_at” cosmetic
    • “report_outcome” reworded the description of “retention_pct” cosmetic
    • “report_outcome” reworded the description of “url” cosmetic
    • “report_outcome” reworded the description of “views” cosmetic
    • “revoke_key” reworded the description of “api_key” cosmetic
    • “revoke_key” reworded the description of “prefix” cosmetic
    • “score_hook” reworded the description of “api_key” cosmetic
    • “score_hook” reworded the description of “idempotency_key” cosmetic
    • “score_hook” reworded the description of “platform” cosmetic
    • “score_hook” reworded the description of “tags” cosmetic
    • “score_hook” reworded the description of “text” cosmetic
    • “score_hook” reworded the description of “verbosity” cosmetic
    • “score_hooks_batch” reworded the description of “api_key” cosmetic
    • “score_hooks_batch” reworded the description of “compare” cosmetic
    • “score_hooks_batch” reworded the description of “idempotency_key” cosmetic
    • “score_hooks_batch” reworded the description of “platform” cosmetic
    • “score_hooks_batch” reworded the description of “sets” cosmetic
    • “score_hooks_batch” reworded the description of “tags” cosmetic
    • “score_hooks_batch” reworded the description of “texts” cosmetic
    • “score_hooks_batch” reworded the description of “verbosity” cosmetic
    • “set_webhook” reworded the description of “api_key” cosmetic
    • “set_webhook” reworded the description of “url” cosmetic
    • “signup” reworded the description of “email” cosmetic
    • “signup” reworded the description of “idempotency_key” cosmetic
    • “signup” reworded the description of “name” cosmetic
    • “start_generate_job” reworded the description of “api_key” cosmetic
    • “start_generate_job” reworded the description of “archetypes” cosmetic
    • “start_generate_job” reworded the description of “count” cosmetic
    • “start_generate_job” reworded the description of “idempotency_key” cosmetic
    • “start_generate_job” reworded the description of “mode” cosmetic
    • “start_generate_job” reworded the description of “platform” cosmetic
    • “start_generate_job” reworded the description of “style” cosmetic
    • “start_generate_job” reworded the description of “tags” cosmetic
    • “start_generate_job” reworded the description of “topic” cosmetic
    • “start_generate_job” reworded the description of “topics” cosmetic
    • “remix_hook” made “target_archetype” optional cosmetic
    • “remix_hook” made “text” optional cosmetic
  • 1 Aug 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 17 to 20. That category is still filling its 30-day observation window: 5 days of observed history at the previous scan, 6 at this one. The score rises as the window fills, whether or not the server changes.

  • 31 Jul 26 +4
    • We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
  • 29 Jul 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.

  • 28 Jul 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 3 to 7. That category is still filling its 30-day observation window: 1 days of observed history at the previous scan, 2 at this one. The score rises as the window fills, whether or not the server changes.

  • 27 Jul 26 0
    • We updated how we score, so this day's move reflects our rubric, not a change to the server See what changed → functional
  • 26 Jul 26 52

    First indexed and scored.

Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 3 Aug 2026 · Probed https://engine-production-3bdc.up.railway.app/mcp

TLS valid

Negotiated TLS 1.3 with TLS_AES_128_GCM_SHA256 .

Subject Issuer Valid from Valid until Key Signature Serial
CN=*.up.railway.app CN=YE1,O=Let's Encrypt,C=US 29 Jul 2026 27 Oct 2026 ECDSA 256 ECDSA-SHA384 6da79bb561da3efeb0e751ca21abd3999fe
SANs: *.up.railway.app, up.railway.app
CN=YE1,O=Let's Encrypt,C=US (CA) CN=Root YE,O=ISRG,C=US 3 Sept 2025 2 Sept 2028 ECDSA 384 ECDSA-SHA384 5ddd70dd31f801c85c186a7a04b80afe
CN=Root YE,O=ISRG,C=US (CA) CN=ISRG Root X2,O=Internet Security Research Group,C=US 13 May 2026 2 Sept 2032 ECDSA 384 ECDSA-SHA384 872165fc34b6e5fba8add5b3705fb53a
CN=ISRG Root X2,O=Internet Security Research Group,C=US (CA) CN=ISRG Root X1,O=Internet Security Research Group,C=US 13 May 2026 2 Sept 2032 ECDSA 384 SHA256-RSA 6c8f1dc727c7117f7baf853ac980f9cd
DNSSEC insecure

Validation of engine-production-3bdc.up.railway.app. Not signed

Zone DS Keys Algorithms Outcome
. trust_anchor 20326, 38696 8, 8 Verified
app. present 23684 8 Verified
railway.app. absent Unsigned (proven) parent-signed NSEC/NSEC3 proves an unsigned delegation
Authentication No authorisation required

The endpoint answered without asking for a token. Anyone who knows the URL can reach it.

Result No authorisation required
HTTP status 200
Header Value
strict-transport-security max-age=31536000
x-content-type-options nosniff
Transports 2 probes
Transport URL Outcome Status Location
streamable-http https://engine-production-3bdc.up.railway.app/mcp Verified 200
http (plaintext) http://engine-production-3bdc.up.railway.app/mcp HTTPS enforced 301 https://engine-production-3bdc.up.railway.app/mcp
MCP tools — 38 exposed · ~12,802 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability.

Tool Tokens
add_credits ~353

Top up your credit balance (1-10000). Self-serve by default. When VHGENGINE_ADMIN_KEY is configured on the deployment this requires a matching admin_key argument; otherwise it stays self-serve (unless VHGENGINE_FREE_CREDITS is off). Idempotent on idempotency_key (replay does NOT grant twice). Returns {credits (new balance), granted}. Errors: unauthorized (missing/wrong admin key or self-serve disabled), invalid_request (amount range / balance ceiling), idempotency_conflict, rate_limited.

NameTypeReqDescription
admin_keyThe deployment's VHGENGINE_ADMIN_KEY. Required ONLY when the operator configured one; omit on a self-serve deployment. A wrong or missing value where one is configured is unauthorized.
amountintegeryesCredits to add, 1-10000. Charged operations spend these; see pricing for the per-mode cost. The grant also has a per-account balance ceiling, so a large top-up on a full balance is invalid_request.
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
idempotency_keyCaller-chosen replay key (any string, unique per intended effect). A repeat call with the SAME key returns the stored result and is NEVER charged twice; the same key with different arguments is an id…
NameTypeReqDescription
creditsnumber|nullBalance AFTER the grant.
grantednumber|nullCredits added by this call; 0 on an idempotent replay.
replayedboolean|nulltrue when an earlier call with the same idempotency_key already granted.

No examples provided.

cancel_job ~242

Cancel a job that is STILL QUEUED. Free, repeatable, never refunds. ALWAYS branch on `cancelled`; reason + next_action say what to do. A queued job was never charged (the worker charges), so credits_refunded is always 0. A RUNNING job cannot be stopped: it finishes, CHARGES and persists. Cancelled reads as status "failed" with error.error.details.cancelled true; to re-run, resubmit with a FRESH idempotency_key (reusing the cancelled one replays the cancelled result). Errors: unauthorized, forbidden (key lacks the spend scope), not_found, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
job_idstringyesThe job to cancel. Account-scoped: an id you do not own reads as not_found, exactly like get_job.
NameTypeReqDescription
already_cancelledboolean|nulltrue when an earlier cancel_job had already cancelled this job, so this call was a no-op rather than a miss.
cancelledboolean|nulltrue only when this call moved a still-QUEUED job to terminal. false means nothing changed; `reason` says why and `next_action` says what to do.
credits_refundednumber|nullAlways 0. A queued job was never charged (the charge runs inside the worker), and a running job cannot be stopped, so a cancel never refunds.
errorNot returned by this tool. Named here because get_job(job_id) afterwards carries error.error.details.cancelled true (code 'conflict', details.reason 'cancelled'): THAT is how you tell your own cancel…
job_idstring|nullThe job the cancel targeted.
next_actionstring|nullThe exact next call to make, if any.
reasonstring|nullWhy the call ended the way it did, in one sentence.
statusstring|nullThe job's status AFTER the attempt: 'failed' when cancelled, else whatever it really is (running / succeeded / failed).

No examples provided.

create_checkout ~298

Get a Stripe hosted-checkout link for a credit pack. You never touch a card (WP-PAY). Hand the returned checkout_url to your human; the webhook credits you after they pay. Args: pack (a credits amount from pricing.credit_packs), success_url/cancel_url (optional), api_key (spend scope). Returns {checkout_url, pack, credits, usd_cents, expires_at}. Errors: unauthorized, forbidden, invalid_request (bad pack), payments_disabled (503; use add_credits), rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
cancel_urlWhere Stripe sends the browser if your human abandons checkout. At most 2048 characters. Omit to use the deployment's default.
packintegeryesWhich credit pack to buy, given as its CREDITS amount and matched against pricing.credit_packs exactly (not a dollar figure and not an index). A value that is not an offered pack is invalid_request.
success_urlWhere Stripe sends the browser after a successful payment. At most 2048 characters. Omit to use the deployment's default landing page.
NameTypeReqDescription
checkout_urlstring|nullThe URL your human opens to pay. Single use.
creditsnumber|nullCredits that land on your balance after the webhook confirms payment.
expires_atstring|nullWhen the checkout link stops working, ISO-8601 UTC.
packnumber|nullWhich pack this session buys.
usd_centsnumber|nullWhat your human is charged, in cents.

No examples provided.

create_key ~335

Mint a new named API key; the plaintext is returned ONCE. Requires admin scope. Delegate safely (WP-SCOPE): optional scopes (subset of read|spend|admin; omit for full power) + daily_credit_cap (credits/day; omit for uncapped) hand a sub-agent a key that can only do what you allow. Args: name (1-100), api_key (an admin-scoped key). Returns {api_key (store it), prefix, name, scopes, daily_credit_cap, created_at}. Errors: unauthorized, forbidden, invalid_request, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
daily_credit_capCredits this key may spend per UTC day, 1-100000; further charges on it are refused once reached (other keys are unaffected). Omit for uncapped. list_keys reports spent_today against this.
namestringLabel for the new key, 1-100 chars, shown by list_keys so you can tell delegated keys apart. Defaults to 'key'.
scopesPowers the new key gets: read (free reads), spend (charged generate/score/remix), admin (key + account + webhook management). OMIT for a full-power key; pass a subset to hand a sub-agent strictly les…
NameTypeReqDescription
api_keystring|nullThe plaintext key. Store it now; it is never readable again.
created_atstring|nullCreation time, ISO-8601 UTC.
daily_credit_capnumber|nullPer-UTC-day spend ceiling, or null for uncapped.
namestring|nullThe label you gave it.
prefixstring|nullFirst 12 chars, used by list_keys / revoke_key / get_usage(key_prefix=...).
scopesarray|nullPowers granted, a subset of read/spend/admin (all three = full power).

No examples provided.

delete_account ~242

Permanently delete this account. TERMINAL, not reversible. Admin scope (WP-LIFE). Pass confirm="delete" (guards an accidental call). Revokes ALL your keys, deletes your hooks, webhook, deliveries, jobs and idempotency rows, KEEPS the immutable financial ledger, and ANONYMIZES your outcomes into the shared corpus. Take what you still want FIRST: export_usage returns the ledger, every hook and every outcome in ONE call (get_usage / list_hooks / list_outcomes are the paged alternative). Errors: unauthorized, forbidden, invalid_request, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
confirmstringyesMust be exactly the string "delete". A guard: any other value (or omitting it) fails argument validation before anything is touched, so an accidental invocation cannot destroy the account.
NameTypeReqDescription
deletedboolean|nulltrue once the account is tombstoned. Every key now 401s.
notestring|nullHuman-readable summary of what was and was not removed.
retainedobject|null{financial_events, anonymized_outcomes}: the immutable ledger is kept and your outcomes are anonymized into the shared corpus rather than destroyed.

No examples provided.

delete_webhook ~117

Remove this account's webhook (WP-M). Admin scope. Args: api_key (admin scope). Cost=free. Returns {deleted: true}. Errors: unauthorized, forbidden, not_found (none registered), rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
NameTypeReqDescription
deletedboolean|nulltrue once removed. No further events are delivered.

No examples provided.

export_usage ~291

Export EVERYTHING this account owns in ONE body: ledger, hooks, outcomes. Free. The take-it-with-you call; make it BEFORE delete_account. Same body as GET /v1/usage/export?format=json (csv is a download shape with no MCP carrier and its columns are a subset of `events`). UNBOUNDED, no paging: on a big account prefer get_usage / list_hooks / list_outcomes. `email` is masked without the admin scope. Returns {account_id, email, count, events, hooks, outcomes}; tag/key_prefix narrow events. Errors: unauthorized, forbidden (key lacks the read scope), rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
key_prefixNarrow the LEDGER to charges made with ONE api key, identified by the 12-char prefix from list_keys. `hooks` and `outcomes` are always the full set and are NOT narrowed by this. Omit for every key.
tagFilter to rows carrying EXACTLY this fleet tag (exact match, not a substring). Omit for every tag.
NameTypeReqDescription
account_idstring|nullYour account id.
countnumber|nullHow many ledger rows `events` carries.
emailstring|nullContact address given at signup, MASKED (z***@d***.com) unless the calling key has the admin scope. Null when none was given.
eventsarray|nullThe FULL charge ledger, oldest first, narrowed by tag/key_prefix. Each {id, created_at, operation, credits_delta, balance_after, request_id, key_prefix, metadata}. This is the superset of the REST cs…
hooksarray|nullEVERY hook this account bought: {hook_id, request_id, topic, mode, platform, text, archetype, claim_type, score_total, score, contains_placeholder_stat, prompt_version, tags, created_at}. NOT narrowe…
outcomesarray|nullEVERY outcome this account reported, each with the hook snapshot taken at report time. NOT narrowed by tag/key_prefix.

No examples provided.

generate_hooks ~800

Generate ranked, scored viral hooks for a topic. Charged by mode. Cost = base + per_hook * hooks_returned (instant 0+1, smart 0+2, research 10+4, ~50 at count=10); a pre-flight gate never bills a broke account. Deterministic only in instant; a progressToken streams stages; the hook id is `hooks[].id`. CANCELLING DOES NOT REFUND: a timeout cannot stop the engine thread, so the call still charges and persists. Send idempotency_key, or recover via list_hooks. Errors: unauthorized, invalid_request, llm_unavailable, insufficient_credits.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
archetypesRestrict generation to these archetype ids (see list_archetypes). Omit to let the engine spread across archetypes, which is what you want unless you are deliberately narrowing a deck.
countintegerHow many hooks to generate, 1-25. Drives the price (base + per_hook * hooks_RETURNED) and the pre-flight reservation, so a high count on research is the expensive combination.
deadline_msMilliseconds you are willing to block, 1000-600000. If the chosen mode's p90 exceeds it the call returns IMMEDIATELY with auto_job:true + a job_id to poll with get_job instead of generating inline. O…
idempotency_keyCaller-chosen replay key (any string, unique per intended effect). A repeat call with the SAME key returns the stored result and is NEVER charged twice; the same key with different arguments is an id…
modeGeneration engine and therefore the price: instant (0 base + 1/hook, deterministic templates, sub-second), smart (0 + 2/hook, one LLM call, seconds), research (10 + 4/hook, brief->draft->judge, tens…
platformstringTarget platform, which selects the length/format conventions the hooks are written and scored against. Defaults to tiktok when omitted.
styleVoice/tone to match, <=200 chars. Honored as a real instruction by smart and research; on instant it only varies which deterministic template fillers are drawn, so it cannot change the voice there. O…
tags1-5 lowercase slug tags ([a-z0-9_-], <=40 chars) stamped on this call's usage event so a fleet can attribute spend per campaign. Omit for no tagging. Filter later with get_usage(tag=...) / list_hooks…
topicstringyesWhat the hooks are about, 3-200 chars. A concrete subject ('cold plunges for desk workers') scores far better than a bare noun; on research it is also what the brief is researched against.
verbositystringHow much of the response envelope to return: minimal (ids/text/totals only), standard (the default), full (adds per-dimension score attribution and timings). Shapes the RESPONSE only, never what is g…
NameTypeReqDescription
auto_jobboolean|nullPresent and true when deadline_ms made this return a JOB instead of hooks. CHECK IT BEFORE READING `hooks`: on this path `hooks` is ABSENT and the body is the job pointer below (job_id, status, estim…
base_pricenumber|nullFixed part of the charge for this mode.
count_requestednumber|nullThe count you asked for, echoed so you never have to diff an array length against your own request.
credits_chargednumber|nullCredits this call actually cost.
credits_remainingnumber|nullYour balance AFTER this charge.
degraded_reasonstring|nullverbosity=minimal ONLY, and only when non-null: hoisted out of `research` so the trimmed envelope still says WHY the run degraded. At standard/full read research.degraded_reason instead.
degraded_stagesarray|nullverbosity=minimal ONLY, and only when non-empty: hoisted out of `research`; which stages to blame. At standard/full read research.degraded_stages.
enginestring|nullWhich generator implementation produced the deck.
estimated_secondsnumber|nullauto_job path only: queue-aware estimate of total time to a result.
expected_waitobject|null{mode, p50_ms, p90_ms, source} for this mode, to size the NEXT call.
expires_atstring|nullauto_job path only: when an unexecuted job is abandoned, ISO-8601 UTC.
grounding_refundobject|nullNon-null ONLY when you asked for research and the VENDOR REFUSED the web-search tool: the full pipeline still ran, so you are not billed as smart, but part of the research premium is waived. {credits…
hintstring|nullauto_job path only: what to do next, in one sentence.
hooksarray|nullRanked hooks, best first. Each is {id, text, archetype, score, claim_type, rank}. NOTE the key is `id`, and THAT is the hook id you pass to report_outcome(hook_id=...) / get_hook (where the same valu…
job_idstring|nullauto_job path only: poll it with get_job or block on wait_for_job.
judge_fallback_reasonstring|nullsmart/research only: why the judge did NOT rank this set, or null when it ran. Non-null means these score.totals are heuristic-scale, so never compare them against a judged run's totals.
llm_fallbackboolean|nulltrue when the requested LLM tier was unavailable and a cheaper engine ran instead; llm_fallback_reason says why. You are billed for what RAN.
llm_fallback_reasonstring|nullWhy the fallback happened, or null.
mode_requestedstring|nullThe mode string you sent, before alias/auto resolution.
mode_usedstring|nullThe engine that actually ran (instant|smart|research) after aliases and auto were resolved. May differ from mode_requested.
poll_after_secondsnumber|nullauto_job path only: wait at least this long before the first get_job.
price_per_hooknumber|nullPer-hook part of the charge for this mode.
pricing_modestring|nullThe tier billed, which is what price_per_hook belongs to.
prompt_versionstring|nullPrompt build used, for reproducibility.
rank_basisstring|nullverbosity=minimal ONLY, alongside degraded_stages: hoisted out of `research`; what the served ORDER means (llm_judge | judge_order_no_scores | heuristic | unranked). At standard/full read research.ra…
reasonstring|nullinstant only, non-null when the template pool ran out: prose saying hooks were WITHHELD rather than duplicated. On a clause-topic it says outright that widening `archetypes` will not help, so do not…
replayedboolean|nulltrue when an idempotency_key replayed a stored result, so nothing was charged again. The credits_charged below is what the ORIGINAL call cost.
replayed_at_chargeboolean|nulltrue when the replay was detected at the charge boundary rather than up front; either way you are billed exactly once.
request_idstring|nullId of this call. Keep it: get_usage(request_id=...) itemises exactly what it charged, and it identifies the call in a support question.
requeuedboolean|nullauto_job path only: true when an idempotent resubmit revived an existing job.
researchmode research ONLY (null on instant/smart). The grounding ledger you paid for. Keys, and what to DO with each: - brief_summary (str), angles (list of {angle, detail, why_it_stops_scroll}), vocabulary…
score_disclaimerstring|nullThe honest limits of the scores above. Absent at verbosity=minimal.
shortfallobject|null{requested, returned, cause} on EVERY response. `cause` is a closed vocabulary: 'none' on a full delivery, else template_pool / model_under_delivery / pool_exhausted. Branch on cause; never retry on…
statusstring|nullauto_job path only: the job's lifecycle state ('queued').
status_urlstring|nullauto_job path only: REST URL for the same status (HTTP clients).
timingobject|nullWhat actually happened: {latency_ms, stages}. `stages` keys are mode specific (instant render_ms; smart llm_ms/judge_ms; research brief_ms/draft_ms/judge_ms).
usageobject|nullLLM token usage {input_tokens, output_tokens, est_cost_usd} (+ web_searches and fallback_* counters when those paths ran). NULL means NO LLM ran, which is not the same as zero tokens.

No examples provided.

generate_hooks_batch ~592

Generate hooks for many topics in ONE call, charged all-or-nothing. One transaction: over-balance charges nothing; each item bills base + per_hook * hooks_returned for the engine that ran (divergent tiers -> pricing_mode "mixed"). One mode + idempotency_key + tags cover the batch; a progressToken streams item i/n; hook ids are results[i].hooks[j].id. CANCELLING DOES NOT REFUND: a timeout cannot stop the engine thread, so the batch still charges and persists. Send idempotency_key. Errors: unauthorized, invalid_request, llm_unavailable, insufficient_credits.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
idempotency_keyCaller-chosen replay key (any string, unique per intended effect). A repeat call with the SAME key returns the stored result and is NEVER charged twice; the same key with different arguments is an id…
modeGeneration engine and therefore the price: instant (0 base + 1/hook, deterministic templates, sub-second), smart (0 + 2/hook, one LLM call, seconds), research (10 + 4/hook, brief->draft->judge, tens…
platformstringTarget platform, which selects the length/format conventions the hooks are written and scored against. Defaults to tiktok when omitted.
requestsarrayyes1-20 items, each {topic, count?, archetypes?, style?}. Per-item `mode` is rejected: mode, tags, verbosity and idempotency_key are set ONCE for the whole batch. Unknown item keys are invalid_request.
tags1-5 lowercase slug tags ([a-z0-9_-], <=40 chars) stamped on this call's usage event so a fleet can attribute spend per campaign. Omit for no tagging. Filter later with get_usage(tag=...) / list_hooks…
verbositystringHow much of the response envelope to return: minimal (ids/text/totals only), standard (the default), full (adds per-dimension score attribution and timings). Shapes the RESPONSE only, never what is g…
NameTypeReqDescription
base_pricenumber|nullFixed part of the charge, or null when pricing_mode is mixed.
credits_chargednumber|nullCredits this call actually cost.
credits_remainingnumber|nullYour balance AFTER this charge.
degraded_anyboolean|nullWider signal than judge_fallback_any: true when any item ran off-tier for any reason, including a partial stage that still delivered a full hook count.
degraded_reasonstring|nullverbosity=minimal ONLY, and only when non-null: hoisted out of `research` so the trimmed envelope still says WHY the run degraded. At standard/full read research.degraded_reason instead.
degraded_stagesarray|nullverbosity=minimal ONLY, and only when non-empty: hoisted out of `research`; which stages to blame. At standard/full read research.degraded_stages.
enginestring|nullThe generator implementation, or 'mixed' when items diverged.
expected_waitobject|null{mode, p50_ms, p90_ms, source} for the batch's tier.
judge_fallback_anyboolean|nulltrue when at least one item's hooks are HEURISTIC-scale because its judge did not rank them. Then results[i].judge_fallback_reason says which, and you must not rank topics by comparing avg(score.tota…
llm_fallbackboolean|nulltrue when ANY item fell back to a cheaper engine or a fallback provider.
llm_fallback_reasonstring|nullWhy the first such fallback happened, or null.
mode_requestedstring|nullThe mode string you sent, before alias/auto resolution.
mode_usedstring|nullThe engine that ran, after aliases and auto were resolved; 'mixed' when items diverged.
price_per_hooknumber|nullPer-hook part of the charge, or null when pricing_mode is mixed.
pricing_modestring|nullThe tier billed across the batch, or 'mixed' when items fell back to different engines. On 'mixed', base_price/price_per_hook are null and each results[i] carries its own.
prompt_versionstring|nullPrompt build used, for reproducibility.
rank_basisstring|nullverbosity=minimal ONLY, alongside degraded_stages: hoisted out of `research`; what the served ORDER means (llm_judge | judge_order_no_scores | heuristic | unranked). At standard/full read research.ra…
replayedboolean|nulltrue when an idempotency_key replayed a stored result, so nothing was charged again. The credits_charged below is what the ORIGINAL call cost.
replayed_at_chargeboolean|nulltrue when the replay was detected at the charge boundary rather than up front; either way you are billed exactly once.
request_idstring|nullId of this call. Keep it: get_usage(request_id=...) itemises exactly what it charged, and it identifies the call in a support question.
resultsarray|nullOne entry per item, in request order: {topic, hooks, pricing_mode, price_per_hook, base_price, credits, grounding_refund, timing, judge_fallback_reason, count_requested, shortfall, reason, research}.…
score_disclaimerstring|nullThe honest limits of the scores above. Absent at verbosity=minimal.
timingobject|null{latency_ms} for the whole batch.

No examples provided.

get_account ~175

Return this account's state + remaining rate-limit budget. Free read. `rate_limit` carries {limit, remaining, reset_epoch, reset_at, window_seconds} for the per-account window, the same budget REST clients read from X-RateLimit-* headers. Pace a fleet off `remaining` instead of discovering the ceiling by taking a rate_limited mid-run; this read itself consumes one of those calls. No API key is ever echoed back. Errors: unauthorized, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
NameTypeReqDescription
account_idstring|nullYour account id.
api_key_prefixstring|nullPrefix of the key that authenticated this call. Never the key itself.
created_atstring|nullAccount creation time, ISO-8601 UTC.
creditsnumber|nullCurrent balance.
emailstring|nullContact address if one was given at signup.
namestring|nullDisplay name given at signup.
rate_limitobject|null{limit, remaining, reset_epoch, reset_at, window_seconds} for the per-account window. Pace off `remaining`; limit 0 means limiting is disabled and remaining/reset are null.

No examples provided.

get_activity ~215

See what this account's agents are doing: in-flight ops + recent ops. Free. `in_flight` merges the live-ops registry (real stage/pct/eta mid-run) with your queued/running jobs; `recent` is the last completed charged ops. Every row has a human-readable message. The REST surface also offers an SSE feed at GET /v1/activity/stream. Args: recent_limit (1-100, default 20), api_key. Errors: unauthorized, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
recent_limitintegerMax completed rows in `recent`, 1-100. Does not limit `in_flight`, which always shows everything currently running.
NameTypeReqDescription
in_flightarray|nullLive operations: the running-ops registry (real stage/pct/eta) merged with your queued and running jobs. Every row has a human-readable message.
recentarray|nullThe last completed charged operations, sized by recent_limit.

No examples provided.

get_estimates ~73

The measured/expected wait per generation mode. Free, no auth. Size a call before spending. Returns {op, modes:{instant|smart|research: {p50_ms, p90_ms, samples, source ("measured" once enough samples, else "default"), advice}}}.

Input schema present but exposes no named parameters.

NameTypeReqDescription
modesobject|nullPer mode {p50_ms, p90_ms, samples, source ('measured' once enough samples exist, else 'default'), advice}.
opstring|nullWhich operation these estimates describe.

No examples provided.

get_hook ~246

Fetch one bought hook in full, including its parsed score. Free (WP-G). Account-scoped: a foreign or unknown id is not_found (no existence leak). Args: hook_id (from a generate/batch/remix response or list_hooks), api_key. Returns {hook_id, text, archetype, claim_type, mode, platform, topic, score_total, score, prompt_version, request_id, created_at, outcomes:[...], outcome_summary:{count, max_views, avg_views}}. Report results with report_outcome. Errors: unauthorized, not_found, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
hook_idstringyesThe hook's id, as returned in the `hooks[].hook_id` of a generate/batch/remix response or by list_hooks. Account-scoped: an id you do not own reads as not_found.
NameTypeReqDescription
archetypestring|nullArchetype it was written in.
claim_typestring|nullWhat kind of claim it makes.
contains_placeholder_statboolean|nulltrue when the text carries an unverified number you must replace before posting (e.g. '90% of people'). Treat as an edit-before-use flag.
created_atstring|nullWhen it was generated, ISO-8601 UTC.
hook_idstring|nullThe hook's id.
modestring|nullEngine that produced it (instant|smart|research|remix).
outcome_summaryobject|null{count, max_views, avg_views} over those outcomes.
outcomesarray|nullOutcomes you have reported against this hook.
platformstring|nullPlatform it was written for.
prompt_versionstring|nullPrompt build that produced it, for reproducibility.
request_idstring|nullThe generate call that bought it.
scoreobject|nullPer-dimension score breakdown.
score_totalnumber|nullTotal craft score.
textstring|nullThe hook line.
topicstring|nullTopic it was generated from.

No examples provided.

get_job ~231

Poll an async job: status, real engine stage, progress, ETA, result/error. Poll after poll_after_seconds until status is "succeeded" (result holds the full generate body) or "failed" (error holds the typed envelope). Only the owning account can read a job; a foreign/unknown id is not_found (no existence leak). Returns {job_id, status, stage, progress_pct, eta_seconds, elapsed_ms, poll_after_seconds, result, error}. Errors: unauthorized, not_found, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
job_idstringyesThe job's id, as returned by start_generate_job (or by a generate_hooks call that auto-jobbed on deadline_ms). Account-scoped: an id you do not own reads as not_found.
NameTypeReqDescription
elapsed_msnumber|nullMilliseconds since the job started running.
errorobject|nullOn failure: the same typed error envelope a synchronous call returns. details.cancelled true means YOU cancelled it with cancel_job, not a fault.
eta_secondsnumber|nullEstimated seconds remaining.
job_idstring|nullThe job polled.
poll_after_secondsnumber|nullHow long to wait before polling again.
progress_pctnumber|null0-100 progress within the run.
resultobject|nullOn success: the FULL generate (or batch) body, always full-verbosity.
stagestring|nullThe real engine stage while running (e.g. brief, draft, judge).
statusstring|nullqueued (waiting on a worker), running, succeeded (see `result`), failed (see `error`). Stop polling on the last two.

No examples provided.

get_usage ~425

Return the credit balance, per-operation totals, and recent ledger. Free. Args: recent_limit (1-200, default 50), offset (>=0, pages `recent` past the newest rows), request_id (scope recent to that call's charges), tag + key_prefix (WP-J fleet filters), api_key. Returns {credits, totals:{by_operation}, recent:[...]} (each row carries key_prefix; tags in metadata). Errors: unauthorized, invalid_request, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
key_prefixFilter to charges made with ONE api key, identified by the 12-char prefix from list_keys (e.g. vhg_sk_ab12). Omit for every key.
offsetintegerRows to skip before `recent` starts, for paging past the newest page. Page with offset += recent_limit, exactly like list_hooks and list_outcomes; an offset past the end is an empty `recent`, never a…
recent_limitintegerMax recent ledger rows to return, 1-200. Totals are unaffected by this; it only sizes `recent`.
request_idScope `recent` to the charges of ONE earlier call: pass the request_id that call RETURNED (or its X-Request-Id header), never a freshly minted id. An id that charged nothing matches no rows and comes…
tagFilter to rows carrying EXACTLY this fleet tag (exact match, not a substring). Omit for every tag.
NameTypeReqDescription
creditsnumber|nullCurrent balance.
recentarray|nullRecent charge rows, newest first, sized by recent_limit. Each carries the operation, credits, key_prefix, request_id and tags in metadata.
totalsobject|null{by_operation: {op: {calls, credits}}} over the whole account lifetime.
unreported_hooksobject|nullHow many bought hooks still have no outcome, i.e. how much free reward is on the table. Find them with list_hooks(unreported=true).

No examples provided.

get_webhook ~133

This account's webhook (url + last delivery status; never the secret). Free read. Args: api_key (read scope). Cost=free. Returns {url, created_at, last_delivery_status, last_delivery_at, events}. Errors: unauthorized, not_found (none registered), rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
NameTypeReqDescription
created_atstring|nullRegistration time, ISO-8601 UTC.
eventsarray|nullEvent types being delivered.
last_delivery_atstring|nullWhen that attempt happened, ISO-8601 UTC.
last_delivery_statusstring|nullStatus of the most recent delivery attempt.
urlstring|nullThe registered endpoint.

No examples provided.

getting_started ~77

The 5-step agent quickstart: modes, wait guidance, links. Free, no auth. Written to be parsed and acted on. Returns {what_this_is, five_steps, modes (cost + live latency + when to use), wait_guidance (expected_wait, estimates, progressToken, jobs), links}.

Input schema present but exposes no named parameters.

NameTypeReqDescription
data_and_deletionstring|nullRetention and what delete_account keeps.
evaluateobject|nullHow to judge output quality, including the public bake-off.
five_stepsarray|nullThe 5 ordered steps from nothing to hooks.
fleet_accountingstring|nullHow tags and per-key caps attribute spend across a fleet.
linksobject|nullDocs and endpoint links.
memory_cardstring|nullA compact block worth persisting into your own memory.
modesarray|nullOne entry PER MODE (a list, not a map): {mode, base, per_hook, formula, p50_ms, p90_ms, latency_source, when_to_use}.
paymentsstring|nullHow to top up: add_credits and create_checkout.
response_shapingstring|nullHow verbosity changes what you get back.
wait_guidanceobject|nullHow to avoid blocking blind: expected_wait, progressToken, jobs.
webhooksstring|nullHow to receive job and low-balance events.
what_this_isstring|nullOne-paragraph description of the service.

No examples provided.

health ~144

Deep health: DB read+write probe, worker/queue, backup + integrity. Free. Same db.write_probe/backup.status/backup.offsite_status/integrity.status calls GET /health makes, so the two can never disagree. status is "ok" only when the DB both reads AND writes. Returns {status, version, time, llm_configured, outcomes_reported_total, job_worker_alive, job_queue_depth, last_backup_at, backup_count, offsite, integrity}. llm_configured never calls an LLM; CHECK job_worker_alive before start_generate_job (false: a queued job never runs).

Input schema present but exposes no named parameters.

NameTypeReqDescription
backup_countnumber|nullHow many daily backups are retained. Null when status is unavailable.
integrityobject|nullWeekly PRAGMA quick_check result: {last_check_at, ok}, both null before the first check has ever run. Null (the whole object) when status is unavailable.
job_queue_depthnumber|nullJobs queued and not yet claimed, across all accounts. Null when status is unavailable.
job_worker_aliveboolean|nullWhether this deployment runs the job worker. FALSE means start_generate_job would queue a job nothing executes: use generate_hooks instead.
last_backup_atstring|nullNewest nightly backup's timestamp, ISO-8601 UTC. Null before the first backup runs, or when status is unavailable.
llm_configuredboolean|nullWhether an LLM key is configured. false means smart/research are unavailable and mode=auto resolves to instant. A pure config read, never a live call.
offsiteobject|nullOff-volume upload health: {enabled, last_upload_at, last_status, remote_retained}. In-memory, no live S3 call. Null when status is unavailable.
outcomes_reported_totalnumber|nullSize of the shared outcome corpus (60s-cached COUNT). Null when status is unavailable.
statusstring|null'ok' only when the DB both READS and WRITES (a write probe, not just a ping); 'unavailable' otherwise.
timestring|nullServer time, ISO-8601 UTC.
versionstring|nullServer version.

No examples provided.

list_archetypes ~77

List the hook archetypes with psychology, platforms, and templates. Free, no auth. Returns {archetypes:[{id, name, description, psychological_trigger, best_for, templates}]}. Use an id for generate_hooks(archetypes=[...]) or remix_hook(target_archetype=...).

Input schema present but exposes no named parameters.

NameTypeReqDescription
archetypesarray|nullEach {id, name, description, psychological_trigger, best_for, templates}. Use `id` for generate_hooks(archetypes=[...]) / remix_hook(target_archetype=...).

No examples provided.

list_billing_events ~251

Recent billing events (usage.recorded, credits.granted, credits.low). Free. Newest first, paged with limit/offset like list_hooks and list_outcomes. Returns {events:[{id, event_type, payload, created_at}], limit, offset, total}. Errors: unauthorized, invalid_request, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
limitintegerMax billing events to return, 1-200. Above the ceiling is an invalid_request, never a silent truncation.
offsetintegerNumber of rows to skip for paging, 0-9223372036854775807. Page with offset += the limit you actually requested; `total` in the response is the unpaged count. The ceiling is SQLite's largest bindable…
NameTypeReqDescription
eventsarray|nullThis page: {id, event_type, payload, created_at}.
limitnumber|nullPage size actually applied.
offsetnumber|nullOffset this page started at.
totalnumber|nullRows matching the filters IGNORING paging.

No examples provided.

list_hooks ~589

List the hooks this account has bought, newest first. Free (WP-G). Persisted hooks stay retrievable for 90 days. Args: mode (instant|smart|research| remix, or any generate alias such as template/search), since (ISO timestamp), tag (exact fleet-tag match), topic (substring), unreported (true: only hooks a first outcome report can still reward), limit (1-100), offset, api_key. Returns {hooks:[{hook_id, text, archetype, mode, score_total, created_at, request_id}], limit, offset, total}. Errors: unauthorized, invalid_request, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
limitintegerMax hooks to return, 1-200. Above the ceiling is an invalid_request, never a silent truncation.
modeFilter to hooks bought from this engine. Canonical stored values: instant|smart|research|remix; the generate aliases (template|off|quick, llm|on|fast, search|deep|deep_research) are accepted and reso…
offsetintegerNumber of rows to skip for paging, 0-9223372036854775807. Page with offset += the limit you actually requested; `total` in the response is the unpaged count. The ceiling is SQLite's largest bindable…
sinceReturn only rows created at or after this UTC timestamp. Compared LEXICALLY against stored 'YYYY-MM-DDTHH:MM:SSZ' values, so pass that exact format (a date-only string or a unix epoch silently select…
tagFilter to hooks carrying EXACTLY this fleet tag: a lowercase slug of 1-40 chars of [a-z0-9_-], matched LITERALLY. `_` is a legal tag character and is NOT a wildcard here, and neither is `%`; there is…
topicCase-insensitive SUBSTRING match against the topic a hook was generated for (unlike `tag`, which is exact). Omit for every topic.
unreportedtrue = only hooks with no outcome yet, i.e. the ones a first report_outcome can still earn a reward on. false = only hooks already reported. Omit for both.
NameTypeReqDescription
hooksarray|nullThis page: {hook_id, text, archetype, mode, score_total, created_at, request_id}. hook_id is what report_outcome and get_hook take.
limitnumber|nullPage size actually applied.
offsetnumber|nullOffset this page started at.
totalnumber|nullRows matching the filters IGNORING paging: the number to page through, not the number returned here.

No examples provided.

list_jobs ~254

List this account's jobs, newest first (summaries without the result blob). Args: limit (1-200, default 50), offset (>=0), api_key. Returns {jobs:[{job_id, status, stage, progress_pct, created_at, started_at, finished_at}], limit, offset, total}. Errors: unauthorized, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
limitintegerMax jobs to return, 1-200. Above the ceiling is an invalid_request, never a silent truncation.
offsetintegerNumber of rows to skip for paging, 0-9223372036854775807. Page with offset += the limit you actually requested; `total` in the response is the unpaged count. The ceiling is SQLite's largest bindable…
NameTypeReqDescription
jobsarray|nullSummaries: {job_id, status, stage, progress_pct, created_at, started_at, finished_at}. Fetch a result with get_job.
limitnumber|nullPage size actually applied.
offsetnumber|nullOffset this page started at.
totalnumber|nullJobs matching ignoring paging.

No examples provided.

list_keys ~170

List this account's API keys as PREFIXES only (never the raw key). Admin scope. Returns {keys:[{prefix, name, scopes, daily_credit_cap, spent_today, created_at, revoked_at}]}, oldest first; revoked_at is null for an active key, scopes lists the key's grant (WP-SCOPE), spent_today is its credits spent since UTC midnight. Your signup key shows as name "default". Errors: unauthorized, forbidden, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
NameTypeReqDescription
keysarray|nullOldest first. Each {prefix, name, scopes, daily_credit_cap, spent_today, created_at, revoked_at}; revoked_at null means still active, and the signup key shows as name 'default'.

No examples provided.

list_outcomes ~430

List the posted outcomes THIS account has reported, newest first. Free (WP-LIFE). Retrieve your own submitted telemetry in bulk (per-hook it rides get_hook). Args: platform (tiktok|instagram|youtube|x|other), since (ISO timestamp), hook_id (one hook), limit (1-200, default 50), offset (>=0), api_key. Each row carries the outcome plus its snapshot (hook_text, topic, mode, archetype, claim_type, score_total, score_source, prompt_version, tags). Returns {outcomes:[...], limit, offset, total}. Errors: unauthorized, invalid_request, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
hook_idFilter to the outcomes reported against ONE hook (its id from list_hooks / a generate response). Omit for every hook.
limitintegerMax outcomes to return, 1-200. Above the ceiling is an invalid_request, never a silent truncation.
offsetintegerNumber of rows to skip for paging, 0-9223372036854775807. Page with offset += the limit you actually requested; `total` in the response is the unpaged count. The ceiling is SQLite's largest bindable…
platformFilter to outcomes reported for one platform. Omit for all.
sinceReturn only rows created at or after this UTC timestamp. Compared LEXICALLY against stored 'YYYY-MM-DDTHH:MM:SSZ' values, so pass that exact format (a date-only string or a unix epoch silently select…
NameTypeReqDescription
limitnumber|nullPage size actually applied.
offsetnumber|nullOffset this page started at.
outcomesarray|nullEach row is the reported outcome plus a snapshot of the hook at report time (hook_text, topic, mode, archetype, claim_type, score_total, score_source, prompt_version, tags).
totalnumber|nullRows matching the filters ignoring paging.

No examples provided.

list_runs ~459

Every call this account was charged for, newest first. Free read. Recover a lost response in two calls, never re-charged: list_runs(request_id=...) for the receipt, then follow `hooks_url` for the hooks it produced. Page with `cursor` (one pass total) or `offset`; stop only when `exhausted` is true, never on a short page. Same composed read GET /v1/runs makes, so the two can never disagree. Errors: unauthorized, invalid_request, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
charged_onlybooleantrue (default): only calls that COST credits. false: also include grants and zero-cost calls.
cursorintegerLedger position to resume scanning from (see `next_cursor` on a prior page); not a run count, not an opaque token. Leave at 0 and follow `next_cursor` to walk your whole history in bounded reads.
limitintegerMax runs to return, 1-200. Above the ceiling is an invalid_request, never a silent truncation.
offsetintegerNumber of rows to skip for paging, 0-9223372036854775807. Page with offset += the limit you actually requested; `total` in the response is the unpaged count. The ceiling is SQLite's largest bindable…
operationReturn only runs of this operation: generate_hooks, generate_hooks_batch, remix_hook, score_hook, score_hooks_batch, add_credits. An unknown value returns an empty page, never an error.
request_idReturn only the run with this X-Request-Id (the response header on every call, including errors). This is the lookup for a lost response whose id you still have.
NameTypeReqDescription
credits_remainingnumber|nullYour balance right now.
exhaustedboolean|nulltrue only when the read reached the END of your ledger. `total` is the COMPLETE count only when this is true.
has_moreboolean|nulltrue when this page is not the whole remainder. Follow `next_cursor` (preferred) or `next_offset`; never infer 'that was all' from a short page.
limitnumber|nullPage size actually applied.
next_cursornumber|nullPass as `cursor` for the next page (leave offset at 0); null when nothing follows. PREFER this over next_offset for a full walk: it resumes exactly where this page stopped instead of re-scanning from…
next_offsetnumber|nullPass as `offset` for the next page; null when nothing follows.
offsetnumber|nullOffset this page started at.
runsarray|nullThis page: {request_id, operation, created_at, credits_delta, credits_charged, balance_after, key_prefix, topic, topics, platform, mode, hooks_returned, tags, hooks_url, usage_url, metadata}. hooks_u…
scan_limitnumber|nullLedger rows one page may examine, however many reads that takes.
scannednumber|nullLedger rows examined to build this page.
totalnumber|nullRows matching the filters WITHIN the scanned window (see `scanned`), not over all history unless `exhausted` is also true.

No examples provided.

list_webhook_deliveries ~383

List this account's webhook deliveries, newest first. Free read (WP-HOOKS). Verify your receiver end-to-end (a webhook.test ping is enqueued at registration) and diagnose failures without waiting out a real event. Args: status (pending|retrying| delivered|dead|retired), limit (1-200, default 50), offset (>=0), api_key. Each row has {delivery_id, event_type, status, attempts, last_status_code, error, timestamps, next_attempt_at, payload_preview (200 chars; the full body is never returned)}. Dead rows are kept 7 days. Errors: unauthorized, invalid_request, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
limitintegerMax deliveries to return, 1-200. Above the ceiling is an invalid_request, never a silent truncation.
offsetintegerNumber of rows to skip for paging, 0-9223372036854775807. Page with offset += the limit you actually requested; `total` in the response is the unpaged count. The ceiling is SQLite's largest bindable…
statusFilter to deliveries in this state: pending (queued, not yet attempted), retrying (failed, backing off), delivered (2xx), dead (retries exhausted; redrive_webhook_delivery can requeue it), retired. O…
NameTypeReqDescription
deliveriesarray|nullEach {delivery_id, event_type, status, attempts, last_status_code, error, timestamps, next_attempt_at, payload_preview (200 chars; the full body is never returned)}. `dead` rows are kept 7 days and c…
limitnumber|nullPage size actually applied.
offsetnumber|nullOffset this page started at.
totalnumber|nullDeliveries matching the filter ignoring paging.

No examples provided.

pricing ~121

The machine-readable price list, with per-mode expected_wait. Free, no auth. Returns {unit, usd_per_credit (0 while credits are free), operations, pricing_modes:{instant:{base:0,per_hook:1},smart:{base:0,per_hook:2}, research:{base:10,per_hook:4}} each with a formula, expected_wait, signup_grant, low_balance_threshold}. A generate charge is base + per_hook * hooks_returned; these are the exact constants the charge path uses.

Input schema present but exposes no named parameters.

NameTypeReqDescription
credit_packsarray|nullBuyable packs; pass one of these credit amounts as create_checkout(pack=...).
expected_waitobject|nullPer-mode {p50_ms, p90_ms, source} latency, same as get_estimates.
low_balance_thresholdnumber|nullBalance at which the credits.low webhook fires.
operationsobject|nullPer-operation costs for the non-generate tools.
payments_enabledboolean|nullfalse when Stripe is not configured: create_checkout then returns payments_disabled and add_credits is the only top-up path.
pricing_modesobject|nullPer mode {base, per_hook, formula, expected_wait}. A generate charge is base + per_hook * hooks_RETURNED.
signup_grantnumber|nullCredits a new account starts with.
unitstring|nullName of the billing unit (credits).
usd_per_creditnumber|nullCash price per credit; 0 while credits are free.

No examples provided.

quote ~455

Price and time a generate BEFORE you commit to it, without spending. Free. Answers what you cannot otherwise learn without paying: which engine will BILL (mode=auto resolves here), credits_max, expected_wait, and whether this key can afford it now (balance AND any daily account/key cap, spelled out in `blocker`). Same validation as generate_hooks, so a bad topic/archetype/mode fails HERE. credits_max is a CEILING (you pay per hook RETURNED) and nothing is reserved. Errors: unauthorized, invalid_request, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
archetypesRestrict generation to these archetype ids (see list_archetypes). Omit to let the engine spread across archetypes, which is what you want unless you are deliberately narrowing a deck.
countintegerHow many hooks you intend to ask for, 1-25. Drives the quoted ceiling: credits_max = base + per_hook * count.
modeGeneration engine and therefore the price: instant (0 base + 1/hook, deterministic templates, sub-second), smart (0 + 2/hook, one LLM call, seconds), research (10 + 4/hook, brief->draft->judge, tens…
platformstringTarget platform, which selects the length/format conventions the hooks are written and scored against. Defaults to tiktok when omitted.
topicstringyesThe topic you intend to generate for, 3-200 chars. It is fully VALIDATED here, so a bad topic is an invalid_request now instead of after you commit to spending.
NameTypeReqDescription
affordableboolean|nulltrue when a generate with these arguments would pass every pre-flight gate (balance AND any daily account/key spend cap). Branch on THIS.
base_pricenumber|nullFixed part of the charge for pricing_mode.
blockerNull when affordable. Otherwise the SAME typed error block generate_hooks would have returned ({code, message, retriable, details, ...}), whose details.hint names the exact fix.
countnumber|nullThe hook count quoted.
credits_maxnumber|nullThe CEILING: base_price + price_per_hook * count. The real charge bills hooks RETURNED, so a short deck costs less. Never more than this.
credits_remainingnumber|nullYour balance right now.
credits_shortnumber|nullHow many credits you are missing; 0 when affordable. Against a daily cap this is the gap to the remaining daily headroom, not to your balance.
expected_waitobject|null{mode, p50_ms, p90_ms, source} for pricing_mode. Compare p90_ms against your own patience to choose sync vs start_generate_job + wait_for_job.
formulastring|nullThe exact charge formula, so you can predict any other count.
llm_configuredboolean|nullWhether this deployment has an LLM key. false means smart/research are unavailable and mode=auto resolves to instant.
mode_requestedstring|nullThe mode string you passed, before resolution; null if omitted.
operationstring|nullThe operation this quote prices ('generate_hooks').
platformstring|nullThe platform quoted.
price_per_hooknumber|nullPer-hook part of the charge for pricing_mode.
pricing_modestring|nullThe tier that will actually be BILLED after aliases and auto were resolved: instant|smart|research. This, not mode_requested, is what the price belongs to.
recommendationstring|nullOne sentence naming the next call to make.
topicstring|nullThe topic as validated (echoed back).

No examples provided.

redrive_webhook_delivery ~240

Requeue a dead-lettered webhook delivery: reset to pending, due now. Admin scope. Valid ONLY on a `dead` delivery (a live receiver that exhausted its retries); any other status is a 409 conflict and a delivery you do not own is not_found. It re-attempts through the normal pipeline and, if it dies again, dead-letters normally. Args: delivery_id (from list_webhook_deliveries), api_key. Returns the refreshed row. Errors: unauthorized, forbidden, not_found, conflict, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
delivery_idstringyesThe delivery to requeue, from list_webhook_deliveries. Only a `dead` row can be redriven; any other status is a conflict and a delivery you do not own is not_found.
NameTypeReqDescription
attemptsnumber|nullAttempts so far; the redrive adds to this count.
created_atstring|nullWhen the delivery was first enqueued, ISO-8601 UTC.
dead_atstring|nullWhen it was dead-lettered, or null once redriven.
delivered_atstring|nullWhen it finally succeeded, or null.
delivery_idstring|nullThe delivery that was requeued.
errorstring|nullLast failure reason, or null.
event_typestring|nullThe event this delivery carries.
last_status_codenumber|nullHTTP status of the most recent attempt, or null.
next_attempt_atstring|nullWhen the pipeline will try again, ISO-8601 UTC. Null on a terminal row.
payload_previewstring|nullFirst 200 chars of the body; the full body is never returned.
statusstring|nullReset to 'pending' and due now.

No examples provided.

remix_hook ~860

Rewrite an existing hook into a target archetype. 2 credits per variant. Args: EXACTLY one of text or hook_id; target_archetype OR its alias archetype (disagreeing spellings are a 400); count, tags, verbosity, api_key, idempotency_key. Deterministic; billed only for variants returned. Returns {original:{text, score}, remixes:[{id, text, archetype, score, rank}], topic_core, reason, score_disclaimer, credits_charged, credits_remaining, request_id}. Errors: unauthorized, invalid_request, not_found, insufficient_credits, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
archetypeAlias for `target_archetype`, spelled the way every hook object in every response spells it. Send either one; sending both is fine only if they are equal, and a disagreement is a typed invalid_reques…
countintegerHow many variants to produce, 1-5, at 2 credits each. You are billed only for variants actually returned.
hook_idRemix a hook you ALREADY bought, by the id a generate/batch/remix response returned (also listed by list_hooks): the stored text is looked up for you, so you do not have to carry it back. Account-sco…
idempotency_keyCaller-chosen replay key (any string, unique per intended effect). A repeat call with the SAME key returns the stored result and is NEVER charged twice; the same key with different arguments is an id…
platformThe platform whose SCORING WINDOW grades these variants, as on generate_hooks and score_hook: LinkedIn's ideal hook length is 10-18 words against 8-14 elsewhere, so it moves both score.total and the…
tags1-5 lowercase slug tags ([a-z0-9_-], <=40 chars) stamped on this call's usage event so a fleet can attribute spend per campaign. Omit for no tagging. Filter later with get_usage(tag=...) / list_hooks…
target_archetypeArchetype id to rewrite INTO (see list_archetypes for ids and their psychology). `archetype` is an accepted alias for this argument; one of the two is required, there is no default angle.
textThe existing hook to rewrite, 3-300 chars. Its subject is kept; only the angle moves to target_archetype. Pass this OR `hook_id`, never both and never neither.
topicThe subject the hook was written FOR, scored as on score_hook: the verbatim-echo penalty only fires when the scorer is told the topic, so a hook (or a variant) that repeats its own subject scores up…
verbositystringHow much of the response envelope to return: minimal (ids/text/totals only), standard (the default), full (adds per-dimension score attribution and timings). Shapes the RESPONSE only, never what is g…
NameTypeReqDescription
credits_chargednumber|nullCredits this call actually cost.
credits_remainingnumber|nullYour balance AFTER this charge.
llm_fallbackboolean|nulltrue when the LLM remixer was unavailable and the deterministic one ran; llm_fallback_reason says why. You are billed for what RAN.
llm_fallback_reasonstring|nullWhy the fallback happened, or null.
originalobject|null{text, score} of what you passed in.
platformstring|nullThe platform scoring window every total above was produced on. Score a variant through score_hook with this SAME platform to reproduce its number; a different window gives a different total and a dif…
reasonstring|nullWhy these rewrites fit the target archetype, or null.
remix_enginestring|nullWhich remixer produced the variants.
remixesarray|nullThe variants: {id, text, archetype, score, rank}. Billed per variant RETURNED, so this can be shorter than count.
replayedboolean|nulltrue when an idempotency_key replayed a stored result, so nothing was charged again. The credits_charged below is what the ORIGINAL call cost.
replayed_at_chargeboolean|nulltrue when the replay was detected at the charge boundary rather than up front; either way you are billed exactly once.
request_idstring|nullId of this call. Keep it: get_usage(request_id=...) itemises exactly what it charged, and it identifies the call in a support question.
score_disclaimerstring|nullThe honest limits of the score attached above.
topic_corestring|nullThe subject the remixer preserved from the original.

No examples provided.

report_outcome ~516

Report what a bought hook actually did once posted. FREE (WP-H). Honest telemetry feeding the outcome corpus (no view prediction claimed). Args: hook_id, platform (tiktok|instagram|youtube|x|other), posted_at (ISO, not >48h future), views/likes (0..1e11), retention_pct? (0-100), url? (http(s)+host), api_key, idempotency_key. Caps 20/hook, 500/day; an exact duplicate is a conflict. Returns {outcome, aggregate, reward_credits, credits_remaining?}. Errors: unauthorized, not_found, invalid_request, conflict, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
hook_idstringyesWhich bought hook this result belongs to: the hook_id from a generate/batch/remix response or list_hooks. Must be a hook you own.
idempotency_keyCaller-chosen replay key (any string, unique per intended effect). A repeat call with the SAME key returns the stored result and is NEVER charged twice; the same key with different arguments is an id…
likesLikes at report time, >=0. Omit if you cannot read it.
platformstringyesWhere the hook was actually posted. Required.
posted_atstringyesWhen it went live, ISO-8601 UTC ('YYYY-MM-DDTHH:MM:SSZ'). May be in the past; more than 48h in the FUTURE is invalid_request.
retention_pctAverage view-through as a PERCENT, 0-100 (not a 0-1 fraction). Omit if the platform does not expose it.
urlPublic http(s) URL of the post, for your own audit trail. Must carry a host; omit entirely rather than passing a placeholder.
viewsintegeryesViews the post had accrued at report time, >=0. Required: it is the only field the corpus calibrates against. Report again later (up to 20 reports per hook) to record how it matured.
NameTypeReqDescription
aggregateobject|nullRolled-up totals for this hook across every report you have made.
credits_remainingnumber|nullYour balance after the reward. Present only when one was granted.
outcomeobject|nullThe stored row, as recorded.
replayedboolean|nulltrue when an idempotency_key replayed a stored report.
reward_creditsnumber|nullCredits granted for this report. Only a hook's FIRST report earns one, so later reports return 0.

No examples provided.

revoke_key ~238

Revoke the key with `prefix` (from list_keys): it stops working, others keep working. Use to kill a leaked or old key. Args: prefix (the 12-char key prefix, e.g. vhg_sk_ab12), api_key (a DIFFERENT active key to authenticate this call). Returns {prefix, name, revoked, revoked_at, already_revoked}. You cannot revoke your LAST active key (create a replacement first). Requires the admin scope. Errors: unauthorized, forbidden, invalid_request (last key), not_found, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
prefixstringyesThe 12-char key prefix to kill, copied from list_keys (e.g. vhg_sk_ab12), NOT the plaintext key. Revoking is idempotent; you cannot revoke your last active key.
NameTypeReqDescription
already_revokedboolean|nulltrue when it was already revoked, i.e. this call changed nothing.
namestring|nullIts label.
prefixstring|nullThe key that was revoked.
revokedboolean|nullWhether the key is now revoked (true after a successful call).
revoked_atstring|nullWhen it was revoked, ISO-8601 UTC.

No examples provided.

score_hook ~598

Score any hook text on 5 dimensions with rewrite tips. 1 credit. Deterministic heuristic scorer (no LLM). Args: text (3-300), platform, topic (optional, reproduces generate's score via the verbatim-echo penalty), tags (1-5 fleet slugs, WP-J), verbosity (full keeps per-dimension attribution), api_key, idempotency_key (replay not re-charged). Returns {score:{...,total}, verdict, suggestions, confidence, disclaimer, credits_charged, credits_remaining, request_id}. Errors: unauthorized, invalid_request, insufficient_credits, rate_limited.

NameTypeReqDescription
api_keyAPI key for this call. Omit to fall back to the Authorization: Bearer / X-API-Key request header (streamable-HTTP only), then the VHGENGINE_API_KEY env var (the stdio default). No key resolvable -> u…
idempotency_keyCaller-chosen replay key (any string, unique per intended effect). A repeat call with the SAME key returns the stored result and is NEVER charged twice; the same key with different arguments is an id…
platformstringTarget platform, which selects the length/format conventions the hooks are written and scored against. Defaults to tiktok when omitted.
tags1-5 lowercase slug tags ([a-z0-9_-], <=40 chars) stamped on this call's usage event so a fleet can attribute spend per campaign. Omit for no tagging. Filter later with get_usage(tag=...) / list_hooks…
textstringyesThe hook line to score, 3-300 chars. Any text is accepted (it does not have to be one VHGENGINE generated) and it is never persisted as a hook you own.
topicThe subject this text was written FOR. Pass the SAME topic string a generate call used and this reproduces the exact score.total that generate served for the hook: the scorer's verbatim-echo penalty…
verbositystringHow much of the response envelope to return: minimal (ids/text/totals only), standard (the default), full (adds per-dimension score attribution and timings). Shapes the RESPONSE only, never what is g…
NameTypeReqDescription
confidencestring|nullHow much weight to put on this score.
credits_chargednumber|nullCredits this call actually cost.
credits_remainingnumber|nullYour balance AFTER this charge.
disclaimerstring|nullThe honest limits of the scorer. Worth surfacing to your human.
replayedboolean|nulltrue when an idempotency_key replayed a stored result, so nothing was charged again. The credits_charged below is what the ORIGINAL call cost.
replayed_at_chargeboolean|nulltrue when the replay was detected at the charge boundary rather than up front; either way you are billed exactly once.
request_idstring|nullId of this call. Keep it: get_usage(request_id=...) itemises exactly what it charged, and it identifies the call in a support question.
scoreobject|nullPer-dimension scores plus `total`.
suggestionsarray|nullConcrete rewrite tips.
verdictstring|nullOne-line read of the total.

No examples provided.