API Reference

Agraris data is available as a static JSON file and through Supabase's auto-generated REST API (PostgREST). This page documents read queries (GET). To publish an agent, use the form at publish.html.

JSON API

The simplest way to read the registry. A single static JSON file holds every published listing, agents and tools alike, newest first. No key is needed. The file is regenerated automatically once a day, and only changes when a listing does, so generated_at stays the same until then. For custom queries or fresher data, use the REST API below.

curl "https://agraris.xyz/api/agents.json"

Shape of the file:

{
  "schema_version": 1,
  "generated_at": "2026-10-16T00:00:00.000Z",
  "count": 2,
  "listings": [
    {
      "id": "…",
      "kind": "tool",
      "name": "…",
      …
      "url": "https://agraris.xyz/agent.html?id=…"
    }
  ]
}

Each entry in listings has exactly these fields. Fields may be added in later versions; a change that removes or renames a field raises schema_version.

Field Type Notes
idstring (uuid)Listing id
kindstringagent or tool
namestringListing name
descriptionstringShort summary
versionstringe.g. "1.0.0"
repo_urlstringLink to source repo
categorystring[]Category / tool tags
demo_urlstring | nullOptional demo link
contract_addressstring | nullOptional address provided by the builder, not verified by Agraris
created_atstring (ISO 8601)When the listing was submitted
approved_atstring | nullWhen it was approved; null for listings from before the review queue
github_starsinteger | nullRefreshed daily from GitHub
github_updated_atstring | nullLast push to the repo
verifiedbooleanMarked "Verified" by Agraris
live_statusstring | nullup, down or null; see Live check
live_checked_atstring | nullWhen the demo link was last checked
wanted_idstring (uuid) | nullThe Wanted request this listing answers
owner_signedbooleantrue while the contract's owner() wallet has a current signature; see Contract owner signature
owner_signed_atstring | nullWhen that signature was received
builder_githubstring | nullLowercase GitHub owner from repo_url; null when the repo is not on github.com. See Builders
urlstringThe listing's page on agraris.xyz

Listings are sorted by when they appeared in the registry (approved_at, or created_at when that is null), newest first. Only approved listings are included. To keep only tools (or only agents), filter on kind, for example with jq:

curl -s "https://agraris.xyz/api/agents.json" | jq '.listings[] | select(.kind=="tool")'

# Agents only
curl -s "https://agraris.xyz/api/agents.json" | jq '.listings[] | select(.kind=="agent")'

A short overview for language models is at llms.txt. Being listed is not an endorsement by Agraris.

Base URL

All agent data lives behind a single endpoint — the agents table — exposed by Supabase's built-in PostgREST.

https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents

Only the agents table is documented here. Other tables in the Agraris database are not publicly readable.

Authentication

Every request must include Agraris's Supabase publishable key. Requests without a key are rejected. All examples on this page already use this key, so you can copy and paste them as-is:

sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm

This is a publishable key, designed to be used in browsers. It only grants what the database's access rules allow. Please don't hammer the API; cache results on your side.

There are two ways to send the key — pick one. Via the apikey header (recommended):

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?select=*" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

Or via the ?apikey= query string — handy for opening directly in a browser:

https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?select=*&apikey=sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm

The fetch version in JavaScript:

const res = await fetch(
  "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?select=*",
  { headers: { apikey: "sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm" } }
);
const agents = await res.json();

Note for curl: curly braces

Array filters use curly braces, e.g. cs.{trading}. curl treats {} as a glob pattern, so URLs like this need one of the following: wrap the URL in quotes and pass the -g flag (--globoff), or encode the braces as %7B and %7D (cs.%7Btrading%7D). Always quote the URL so the shell doesn't interpret &, *, and {}. Browsers and fetch encode curly braces automatically.

List all agents

Fetch every agent in the registry, with all columns. Only approved agents are returned; see Review queue.

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?select=*" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

# query string version
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?select=*&apikey=sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

Get a single agent

Filter by id (uuid) to fetch a single agent. Replace AGENT_ID with the id of the agent you want.

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?id=eq.AGENT_ID&select=*" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

Filter by category

The category column is an array (text[]), so ?category=eq.trading won't match. Use the cs (contains) operator to find agents with a given tag.

curl -g "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?category=cs.{trading}" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

# query string version, braces encoded (no -g)
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?category=cs.%7Btrading%7D&apikey=sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

Verified agents only

For regular columns, use eq (equals). For example, only agents marked Verified:

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?verified=eq.true" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

# query string version
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?verified=eq.true&apikey=sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

Other PostgREST operators such as neq, gt, lt, ilike, and is work too — for example ?name=ilike.*bot* for a case-insensitive name search.

Agents or tools

The registry lists two kinds of entries in the same table. The kind column is agent or tool (tools, MCP servers, APIs, SDKs and similar). A request without a kind filter returns both, so add one if you only want agents:

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?kind=eq.agent" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

# only tools
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?kind=eq.tool" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

Filter by contract address

contract_address is optional and empty for most agents. Use is to list only agents that have one:

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?contract_address=not.is.null&select=id,name,contract_address" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

To look up a specific address, use ilike so the match ignores upper/lower case (builders may enter checksummed or lowercase addresses):

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?contract_address=ilike.0x467b7a85f55bd716cb16d59f63b8ccac08852a6c" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

The address is provided by the builder. Agraris does not verify ownership. The Agraris API itself returns only the stored address, never on-chain data.

On-chain activity on agent pages

When an agent has a contract_address, its page shows an "On-chain activity" section. The visitor's browser reads it directly from the public Blockscout API for Robinhood Chain; it does not go through Agraris or Supabase:

https://robinhoodchain.blockscout.com/api/v2/addresses/{address}
https://robinhoodchain.blockscout.com/api/v2/addresses/{address}/counters
Shown as Blockscout field Notes
Address typeis_contract"Contract" or "Not a contract"
Contract namenameShown only when it is a non-empty string
Source verifiedis_verified"Yes" or "No"; shown only when it is a boolean
Transactionstransactions_countFrom /counters; a string such as "1164"
Token transferstoken_transfers_countFrom /counters; a string

The response's hash is compared with the stored address without regard to upper/lower case (Blockscout returns the checksummed form). The numbers are shown as Blockscout reports them, without interpretation. A missing or unexpected field hides only its own row. Neither endpoint returns a last-activity date, so none is shown. If the request fails, is blocked, or takes longer than 6 seconds, the section is hidden and the rest of the page is unaffected.

Select columns

Use select to fetch only specific columns, comma-separated. Responses get smaller and faster.

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?select=name,category,github_stars" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

# query string version
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?select=name,category,github_stars&apikey=sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

Sort

Use order=column.asc or order=column.desc. For example, sort by most GitHub stars (add .nullslast so agents without star data yet go at the end):

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?order=github_stars.desc.nullslast" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

# query string version
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?order=github_stars.desc.nullslast&apikey=sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

Limit & pagination

Use limit to cap the number of rows, and offset for the next page.

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?limit=10" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

# query string version
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?limit=10&apikey=sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

# second page
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?limit=10&offset=10" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

Combining parameters

All of the parameters above can be combined in a single request with &. Example: the 5 trading agents with the most GitHub stars, with only the columns you need.

curl -g "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?select=name,category,github_stars&category=cs.{trading}&order=github_stars.desc.nullslast&limit=5" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

# query string version, braces encoded (no -g)
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?select=name,category,github_stars&category=cs.%7Btrading%7D&order=github_stars.desc.nullslast&limit=5&apikey=sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

The same request with fetch:

const params = new URLSearchParams({
  select: "name,category,github_stars",
  category: "cs.{trading}",
  order: "github_stars.desc.nullslast",
  limit: "5",
});

const res = await fetch(
  `https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?${params}`,
  { headers: { apikey: "sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm" } }
);
const topTradingAgents = await res.json();

Response schema

Each row in the agents table has the following columns.

Column Type Notes
iduuidPrimary key
nametextAgent name
descriptiontextShort summary of the agent
versiontexte.g. "1.0.0"
repo_urltextLink to source repo
categorytext[]Array of category / tool tags
demo_urltextNullable
created_attimestamptzWhen the agent was published
verifiedbooleanMarked "Verified" by Agraris
github_starsintegerNullable; refreshed daily from GitHub
github_updated_attimestamptzNullable; last push to the repo
contract_addresstextOptional; contract or wallet address (0x + 40 hex) provided by the builder, not verified by Agraris
kindtextagent or tool; filter with ?kind=eq.tool
live_statustextNullable; up or down, see Live check
live_checked_attimestamptzNullable; when the demo link was last checked
live_fail_countintegerFailed checks in a row (0 after a success)
wanted_iduuidNullable; the Wanted request this listing answers. Set only when the listing is submitted
approvedbooleanAlways true in API responses; pending entries are not returned

Live check

Every 6 hours Agraris requests the demo_url of each published listing that has one (a plain GET over https, with the User-Agent AgrarisLiveCheck/1.0 (+https://agraris.xyz)). An HTTP 2xx or 3xx answer sets live_status to up. A failure only counts up live_fail_count; live_status becomes down after 3 failed checks in a row, and one success sets it back to up. live_status is null until a listing's demo link has been checked, and is reset when the demo link changes. Listings without a demo link are never checked and show nothing.

This only means the demo URL responded. Not an endorsement: it says nothing about what the demo does or about the listing itself. Nothing from the response is stored. On the site, the search page's "Demo responding" filter keeps listings whose live_status is up.

curl -s "https://agraris.xyz/api/agents.json" | jq '.listings[] | select(.live_status=="up")'

Recently updated

Listings whose builders edited them through "Edit listing" in the last 30 days, latest edit first, one entry per listing. Only approved listings are included, and only edits made after a listing was published count. The function returns id, name, kind and last_edited_at, nothing about what was changed. p_limit defaults to 5 and is capped at 20.

curl -X POST "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/rpc/get_recently_updated" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm" \
  -H "Content-Type: application/json" \
  -d '{"p_limit": 5}'

Wanted board

On wanted.html anyone can describe an agent or tool they need, without an account. Requests are reviewed before they appear, are listed for 60 days, and carry no contact details. Builders answer by publishing a listing with wanted_id set to the request's id ("I built this" opens publish.html?wanted=<id>). Only requests that are currently listed can be answered, and wanted_id cannot be changed after submitting.

get_wanted returns the listed requests, newest first: id, title, description, kind (agent, tool or any), created_at and answers_count (approved listings that answer it). p_limit is capped at 50.

curl -X POST "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/rpc/get_wanted" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm" \
  -H "Content-Type: application/json" \
  -d '{"p_limit": 50}'

# Listings that answer one request
curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/agents?wanted_id=eq.REQUEST_ID&select=id,name,kind" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

New requests go through submit_wanted (p_title up to 100 characters, p_description up to 500, p_kind). Links and web addresses are rejected, and new requests are paused while 20 are waiting for review.

Contract owner signature

A builder whose listing has a contract address can show that the wallet returned by the contract's owner() signed a message. This starts from the listing's status link on status.html, with a browser wallet (personal_sign, EIP-191). The message is made by the database and names agraris.xyz, the listing id, the contract address, chain ID 4663, a one-time nonce and an expiry 10 minutes ahead.

The signature is checked on our server, not in the browser: a GitHub Actions workflow recovers the signing address and reads owner() from Robinhood Chain (chain ID 4663). The listing gets the label "Contract owner signed a message" only when both match and the owner is a regular wallet. Contracts without owner(), with a zero owner, or whose owner is another contract (for example a multisig) can't be shown this way. The owner is read again every 6 hours, and the label is removed when it changes or when the listing's contract address changes.

Only means the owner wallet signed a message. Not an endorsement. It is separate from the manual verified flag.

Current signatures are readable in owner_proofs (agent_id, signer, signed_at; approved listings only), and as owner_signed / owner_signed_at in the JSON file.

curl "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/owner_proofs?select=agent_id,signer,signed_at" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm"

curl -s "https://agraris.xyz/api/agents.json" | jq '.listings[] | select(.owner_signed)'

Builders

builders.html lists every GitHub account that has at least one approved listing, in alphabetical order, and builder.html?u=<owner> shows that account's listings. The account is read from each listing's repo_url: only https://github.com/<owner>/<repo> (or www.github.com) counts, the owner is lowercased and must match ^[a-z0-9-]{1,39}$. Other repo links have no builder.

Grouped by the GitHub owner in each listing's repo URL. Anyone can list a repo, so this does not show who submitted it. Not an endorsement.

The same value is builder_github in the JSON file:

curl -s "https://agraris.xyz/api/agents.json" | jq '.listings[] | select(.builder_github=="OWNER")'

Review queue

New agents submitted through the publish form are saved with approved = false and wait for review before they appear anywhere public. Until then they are left out of every API response (including a lookup by id), the site, the embed widget, the RSS feed, the sitemap and the weekly digest.

The public key can submit new agents but cannot approve them: inserts with approved or verified set to true are rejected, and updates are not allowed.

Because a pending row is not readable with the public key, a submission must not ask for the inserted row back. With supabase-js, call .insert() without .select(); over REST, keep the default Prefer: return=minimal.

To let builders follow their submission, the publish form sends a random status code (status_token, a uuid made in the browser) with the insert and links to status.html. Only a hash of the code is stored, so the column is no use to anyone reading the table. The status page asks for the status with the get_submission_status function, which returns only status (pending or approved), name and id, and nothing when the code does not match.

curl -X POST "https://gnydurjxrynqcbpkxopd.supabase.co/rest/v1/rpc/get_submission_status" \
  -H "apikey: sb_publishable_4roHAzTOTw9P0_8NXKt2IA_kXniR9pm" \
  -H "Content-Type: application/json" \
  -d '{"p_token": "STATUS_CODE"}'

When an agent is approved, approved_at records the time. The RSS feed, the sitemap and the weekly digest date each agent by when it appeared in the registry: approved_at, or created_at for agents listed before the review queue. The owner is emailed about new submissions and approves or rejects them from a GitHub Actions workflow; a rejected submission is deleted.

Rate limits & fair use

This API shares capacity with the Agraris site's own traffic, so there is no published quota. Please use it fairly — cache results on your side if you fetch repeatedly, and avoid aggressive polling.

Embed widget

Show an agent's card on your own site with an <iframe>. The card shows the name, a two-line description, category tags, GitHub stars, the Verified badge (when the agent has it) and a "View on Agraris" link. Each agent page has a ready-to-copy snippet under "Embed this agent".

Parameter Values Notes
idagent uuidRequired. The same id as in agent.html?id=.
themelight | darkOptional, defaults to light. The card's page background is transparent.
<iframe id="agraris-embed"
  src="https://agraris.xyz/embed.html?id=AGENT_ID&theme=dark"
  width="420" height="180" style="border:0" loading="lazy"></iframe>

The card reports its height to the parent page with postMessage, so you can resize the iframe to fit:

window.addEventListener("message", (e) => {
  if (e.origin !== "https://agraris.xyz") return;
  if (e.data?.type !== "agraris-embed-height") return;
  document.querySelector("#agraris-embed").height = e.data.height;
});

GitHub READMEs don't support iframes. For a README, use the "Listed on Agraris" badge from the agent page instead.