Using the VIP API from a coding agent
How a coding agent uses the Monkeymaxxing VIP API: searching flaws in
Debian and Ubuntu packages, and sending a support message to a person at
Monkeymaxxing, with curl and one key.
The VIP API is at https://api.monkeymaxxing.com. A coding agent, such as
Claude Code or Codex, calls two of its routes:
- To check flaws in Debian and Ubuntu packages, call
GET /vulnerabilities/search. - To reach Monkeymaxxing support, send
POST /support-messageswith your diagnosis and what you tried.
MMHotline and MMWatchdog call the API's other routes themselves, with the team's system key; an agent never needs those.
The key
The agent sends a key as a bearer token, read from the environment
variable MONKEYMAXXING_VIP_API_KEY:
curl --silent \
--header "Authorization: Bearer $MONKEYMAXXING_VIP_API_KEY" \
...
Keys are created on the members' website at vip.monkeymaxxing.com, under Keys. The website shows a new key once.
- A personal key belongs to one person and goes into that person's own coding agent. A support message sent with it comes from that person, and the reply goes to them.
- A shared agent key belongs to the team and goes into a coding agent that belongs to the team, such as the triage agent that MMHotline starts. It keeps working when a person leaves the team. The reply to a support message sent with it goes to the team's support contact: the owner, unless the owner names another member.
Never put a key into a repository, a log, or a support message.
Searching flaws in Debian and Ubuntu packages
GET /vulnerabilities/search finds the known flaws in the source packages
of one release. This search asks for the flaws in openssh and php8.5 on
Ubuntu 26.04 that were published on or after 2026-10-21:
curl --silent --get \
--header "Authorization: Bearer $MONKEYMAXXING_VIP_API_KEY" \
--data-urlencode "distribution_release=ubuntu-26.04" \
--data-urlencode "packages=openssh,php8.5" \
--data-urlencode "published_since=2026-10-21" \
https://api.monkeymaxxing.com/vulnerabilities/search
--get puts each field into the query string, and --data-urlencode
encodes it, so that + in a name such as gtk+3.0 is not read as a space.
The releases VIP covers
distribution_release |
Release | Free security fixes end |
|---|---|---|
debian-12 |
Debian 12 (bookworm) | 2028-06-30 |
debian-13 |
Debian 13 (trixie) | 2030-06-30 |
ubuntu-24.04 |
Ubuntu 24.04 LTS (noble) | 2029-05-31 |
ubuntu-26.04 |
Ubuntu 26.04 LTS (resolute) | 2031-05-29 |
VIP adds each new Debian release and Ubuntu LTS release when it comes out. The data comes from Debian's security tracker and Ubuntu's CVE tracker, as OSV.dev publishes them, and from CISA's list of known exploited vulnerabilities. VIP updates it every hour.
The fields
Each field is a query parameter:
distribution_release, required: a value from the table above.packages, optional: source package names, separated by commas. At most 12,000 characters after URL encoding, which holds about 1,000 names; split a longer list over several searches. Withoutpackages, the search covers every source package of the release.published_since, optional: only flaws published at or after this time. A date, such as2026-10-21, means 00:00 UTC on that day; a time is in RFC 3339 format, such as2026-10-25T06:00:00Z.search_text, optional, 1 to 200 characters: only flaws whose CVE ID, description, or CISA name contains every word. A CVE ID, such asCVE-2025-32463, finds that flaw.only_on_cisa_known_exploited_list, optional:truereturns only flaws that attackers are known to exploit.results_per_page, optional: 1 to 500, 100 when left out.page_cursor, optional: the previous answer'snext_page_cursor, for the next page.
Any other parameter is refused with 400 field_invalid. In particular, VIP
never takes a version: the agent compares versions on the server itself,
so VIP never learns whether a server is patched.
Source package names
Debian and Ubuntu record each flaw against the source package that the
binary packages are built from. The binary packages openssh-server and
openssh-client are both built from the source package openssh. The
source packages of everything installed on a server:
dpkg-query --show --showformat='${source:Package}\n' | sort --unique
-
The running kernel is recorded under the source package that its image package names in its
Built-Usingfield, such aslinuxon Debian 13:dpkg-query --show --showformat='${Built-Using}\n' "linux-image-$(uname -r)"On Debian 13 this prints a line such as
linux (= 6.12.113-1): the source packagelinuxat version6.12.113-1. -
Send only packages installed from Debian's or Ubuntu's own archives. A package from another apt repository, such as
caddyfrom Caddy's repository, can have the same name but its own versions. -
A name that is not a source package comes back in
names_not_found_as_source_packages, with the source package it is built from when it is a binary package:"names_not_found_as_source_packages": [ {"name": "openssh-server", "built_from_source_package": "openssh"} ]
The answer
{
"what_was_searched": "Searched Ubuntu 26.04 source packages in Ubuntu's CVE tracker, including fixes that need Ubuntu Pro, as OSV.dev publishes it, and CISA's list of known exploited vulnerabilities. Not searched: packages from other apt repositories, programs that were downloaded or built from source, container images, and the libraries of your apps.",
"vulnerability_data_updated_at": "2026-10-26T07:05:12Z",
"vulnerabilities": [
{
"cve_id": "CVE-2026-109618",
"distribution_release": "ubuntu-26.04",
"source_package": "php8.5",
"fixed_version": "8.5.4-0ubuntu1.5",
"fixed_version_with_ubuntu_pro": null,
"published_at": "2026-10-21T14:00:00Z",
"description": "out-of-memory handling can interrupt PHP while internal request data is only partially initialized.",
"debian_urgency": null,
"ubuntu_priority": "critical",
"ubuntu_priority_reason": "This is a remote code execution vulnerability",
"ubuntu_repository": "main",
"cvss_vectors": [],
"cisa_known_exploited_list_entry": null,
"security_tracker_url": "https://ubuntu.com/security/CVE-2026-109618"
}
],
"names_not_found_as_source_packages": [],
"next_page_cursor": null
}
what_was_searchedsays what VIP searched and what it did not. A search that finds nothing means nothing was found in those sources, not that the server is safe.vulnerability_data_updated_atis when the data was last updated.vulnerabilitieslists the flaws, newest first.next_page_cursorisnullon the last page.
Deciding whether a server is affected
Compare the version on the server with the entry's fixed versions, with
dpkg --compare-versions. The installed version of a source package:
dpkg-query --show --showformat='${source:Version}\n' sudo
A server's package is not affected when fixed_version is not null
and the installed version is at least fixed_version, or when
fixed_version_with_ubuntu_pro is not null and the installed version is
at least that. Otherwise it is affected, in one of three cases:
- A fixed version waits to be installed:
fixed_versionis notnull. - The fix needs Ubuntu Pro:
fixed_versionisnull, andfixed_version_with_ubuntu_prois not. - No fix yet: both are
null.
For example, dpkg --compare-versions 1.9.16p2-3 ge 1.9.16p2-3 succeeds,
so a Debian 13 server with sudo 1.9.16p2-3 is not affected by a flaw
fixed in 1.9.16p2-3.
How serious an affected package is depends on the server: whether it faces the internet, and whether the flawed feature is in use. That judgment is the agent's, because the agent can look at the server.
What VIP does not cover
VIP covers Debian and Ubuntu packages only. It does not cover packages from other apt repositories, programs that were downloaded or built from source, container images, or your app's libraries. Check those in the triage agent's daily software review and in your CI, with a scanner such as Trivy, Dependabot, or osv-scanner.
Sending a support message
When the agent meets a problem with MMX, MMWatchdog, MMHotline, the Fleet conventions, or VIP that the documentation does not solve, it sends a support message. A person at Monkeymaxxing answers by email during US business hours.
curl --silent \
--header "Authorization: Bearer $MONKEYMAXXING_VIP_API_KEY" \
--header "Content-Type: application/json" \
--data @support-message.json \
https://api.monkeymaxxing.com/support-messages
support-message.json:
{
"client_support_message_id": "triage-2026-10-26-replica-lag",
"subject": "db02 stopped replicating after an MMX run",
"diagnosis": "After `mmx run playbooks/postgres.yml` at 07:40 UTC, db02 stopped replicating. pg_stat_replication on db01 shows no rows. The Postgres log on db02 says: password authentication failed for user \"replicator\".",
"what_was_tried": "Checked that db02 reaches db01 on port 5432. Ran the playbook again with --dryrun: it plans to remove the line for db02 again."
}
client_support_message_id: 1 to 64 letters, digits,-, and_, chosen by the agent and unique within the team. Sending the same message again with the same ID, after a timeout, sends no second email.subject: 1 to 150 characters on one line.diagnosis: 1 to 20,000 characters: what the agent found, with the versions, commands, and log lines that matter.what_was_tried: 1 to 20,000 characters: what the agent or its person already tried, and what happened. "Nothing yet." is fine.
Leave out keys, passwords, and personal data that the problem does not need.
The answer:
{
"support_message": {
"support_message_id": "8f14e45fceea167a5a36dedd4bea2543",
"client_support_message_id": "triage-2026-10-26-replica-lag",
"accepted_at": "2026-10-26T08:00:00Z",
"reply_to_email_address": "[email protected]",
"priority_support": true
}
}
reply_to_email_addressis where the reply goes. The agent tells its person this address, because the conversation continues by email.priority_supportistruefor VIP Startup, Growth, and Scale, which get a reply from a person by the next US business day.
A team can send at most 10 support messages an hour; the 11th gets
429 rate_limited. A person can always write to
[email protected] directly.
Errors
Every error answer has this body:
{
"error_code": "field_invalid",
"error_message": "subject must contain 1 to 150 characters.",
"field": "subject"
}
| HTTP status | error_code |
What the agent does |
|---|---|---|
400 |
field_invalid |
Fixes the field that field names, then sends the request again |
400 |
distribution_release_not_covered |
Stops: VIP does not cover that release; the message names the ones it covers |
401 |
credential_rejected |
Stops and tells its person that the key is wrong or was deleted |
403 |
membership_inactive |
Stops and tells its person that the team's VIP membership has ended; for support, writes to [email protected] |
403 |
not_allowed |
Stops: this kind of key may not use this route |
429 |
rate_limited |
Waits for the seconds in Retry-After, then sends the request again |
500 |
internal_error |
Sends the request again after a minute |
503 |
try_again_shortly |
Waits for the seconds in Retry-After, then sends the request again |
Every answer carries the header Monkeymaxxing-Vip-Request-Id. Quote it in
a support message about a failed request.
What VIP keeps
VIP keeps no search text and no package names from a search. A support message stays in VIP's email outbox until 30 days after it was sent, and then lives only in the support mailbox. The privacy policy has the details, and what VIP includes describes the membership.