Acceptance rules for a submitted service

What a service must satisfy before it is listed on the agentic portal. scripts/audit_services.py checks every rule below on the live network and cites the rule code in each finding; the developer-facing version is the docs page Submit a Service (https://docs.pocket.network/services/submit/ once published; until then this reference is served at https://mcp.pocketmcp.network/audit/rules). The protocol itself is permissionless and enforces none of this. These are the portal's listing rules, and they exist so a service that is listed can actually be called through a gateway and paid for.

Three levels. FAIL blocks acceptance. WARN is reported, must be answered by the submitter, and does not block. SKIP means the rule could not be evaluated because an earlier rule failed.

CodeRuleLevelWhy
A1The service ID is registered on the submitted network.FAILNothing else can be checked without the record. IDs are permanent, so a typo here is a new service.
A2The on-chain card is present, decodes as one UTF-8 JSON object, and passes the pocket-service-card/v1 schema. Under 4 KiB.FAIL on schema errors; WARN on convention gapsThe card is the only thing gateways, suppliers, and consumers read. A missing or invalid card means nobody can route, serve, or call the service. Convention gaps (results, updated, specs[].api, the JSON-object statement in the description) are warnings.
A3Every apis[] value is unique within the submission and not claimed by another card on the same network.FAILapis[] is what a gateway keys on to group interchangeable services. A duplicate silently merges two services in every consumer's eyes.
A4At least one active supplier is staked for the service. If the submission names an operator, that operator is among them and is not unbonding.FAILA registered service with no supplier serves nothing.
A5Every staked endpoint is an https:// URL on a hostname, not a bare IP, and its rpc_type is one of the card's rpc_types.FAILGateways connect to the staked URL as given. Plain HTTP or an IP address is refused by the public gateway's TLS policy, and a mismatched rpc_type routes the wrong protocol at the backend.
A6The endpoint answers over TLS with a publicly trusted certificate. Any HTTP status counts; a RelayMiner answers 400 to an unsigned request.FAILA staked URL that does not answer is a supplier that will be scored down from the first session.
A7At least one settled claim exists for the service on the submitted network, and one by the named operator if given. The audit reads settlement history from the indexer, because the LCD lists a claim only until it settles.FAIL; on MainNet, WARN if the newest settlement is older than 7 days (not checked on Beta, where a tested service sees no further traffic)The only on-chain proof that a relay went through the protocol, reached the backend, was signed, claimed, and paid. It is the submitter's job to produce it before submitting: stake an application for the service, send a relay with pocket-ap or the Service Manager's Test step, and wait for settlement.
A8Card and record content: the on-chain display name is human-readable, not a slug or a copy of the ID; an identity probe whose expect pins the response to this service ID; at least one functional probe beyond health and version; every specs[].url resolves; the spec is per service, not shared across a submission; the spec kind is machine-readable (openapi) before MainNet.WARNThe portal shows the display name, and an edit-service batch can silently overwrite it with an internal slug (it happened to a 40-service batch on 2026-09-17). A probe that pins a different name than the service ID either fails on a correct backend or passes on the wrong one. Health-only probes prove the container is up, not that the service works. A shared README is not a contract.
A9compute_units_per_relay is priced with the live multiplier and granularity, reported in uPOKT per relay, and placed in the catalog; a price above the 95th percentile is flagged. The same price across a batch is normal: developers launch batches at one price.WARNAn outlier price is not wrong, but the submitter should be able to say why.

What the audit cannot check

Running the audit

python scripts/audit_services.py --manifest submission.json --json audit.json
python scripts/audit_services.py <id> [<id> ...] --network beta --operator pokt1...

The manifest is templates/submission.json. The report it writes is the record of what was accepted and when. Re-audit accepted services on a schedule with --baseline <last report>; the diff names every verdict change, card rewrite, price change, endpoint change, supplier change, and settlement count, and a regression makes the exit code non-zero. The same rules run on the remote MCP server as the audit_services tool, as a self-service page at https://mcp.pocketmcp.network/audit, and as JSON at GET https://mcp.pocketmcp.network/api/audit?network=beta&ids=<id,id>&operator=<pokt1...>; developers should run one of these before submitting.

Recording a decision

Keep the submission manifest and the audit report together. When a submission is accepted, add its services to the accepted manifest that the scheduled re-audit reads; when one is withdrawn or delisted, remove it there. Never edit a past report.