Skip to content

Add GET /sent-emails/{id}/reply (awaitReply) to the OpenAPI spec - #362

Merged
poiley merged 2 commits into
mainfrom
spec-await-reply
Aug 6, 2026
Merged

Add GET /sent-emails/{id}/reply (awaitReply) to the OpenAPI spec#362
poiley merged 2 commits into
mainfrom
spec-await-reply

Conversation

@poiley

@poiley poiley commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

What

Adds GET /sent-emails/{id}/reply (operationId awaitReply) to openapi/primitive-api.yaml and regenerates all downstream artifacts (node, python, go).

Why

The route has been live in the API for a while: the mono-repo v1 manifest marks it openapi: true and outbound-read.ts serves it. But the spec in this repo is hand-maintained (it is the single source of truth for the SDKs, nothing generates it from the server contract), and this path was simply never authored here. Result: none of the three generated SDKs exposed the canonical "did a reply arrive for this send?" call, even though the MCP server (contract-driven) already exposes it as awaitReply.

The path entry is authored faithfully from the server contract (outboundReadContract.awaitReply in packages/core-api-contract):

  • wait boolean query param (server accepts literal true/false strings), wait_timeout_ms int 1000..30000, server default 10000. No OpenAPI default on purpose, matching the /emails wait param note about generators that send defaults on every call.
  • Response: SuccessEnvelope with AwaitReplyResult (sent_email_id, nullable reply, waited, timed_out), strict like the contract schema.
  • New ReplyEmail component mirrors the contract's ReplyEmailSchema (open object, status left as an open string because the contract does not narrow it).
  • 400/401/404 responses match the handler (404 on ids the org does not own).

Verified against staging: the route answers 401 unauthorized without a key, confirming it is served.

Checks

make node-check cli-check python-check go-check shared-check all pass locally. Generated files committed together with the source edit per the pre-commit gate.

Follow-ups: other openapi:true manifest routes still missing from the spec

Diffing the mono-repo v1 manifest (openapi: true entries, staging) against this spec found five more served-but-unspecified routes, not fixed here:

  • POST /domains/{id}/dns/check
  • POST /endpoints/{id}/rules/test
  • GET /outbound/status (MCP already exposes getOutboundStatus)
  • PATCH /sent-emails/{id} (reschedule a scheduled send)
  • POST /sent-emails/{id}/cancel (MCP already exposes cancelScheduledSend)

🤖 Generated with Claude Code

The route has been live in the API (manifest openapi: true, served by
outbound-read) but was never added to primitive-api.yaml, so none of
the generated SDKs exposed it. Author the path entry faithfully from
the server contract (AwaitReplyQuerySchema, AwaitReplyResponseSchema)
and regenerate the node, python, and go artifacts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

docfacts impact

⚠️ 3 known-wrong doc claims cite code this PR touches — if you're changing this behavior, fix the docs in the same breath:

  • contradicted The Webhook deliveries area provides GET /webhooks/deliveries, GET /webhooks/deliveries/{id}, and POST /webhooks/deliveries/{id}/replay endpoints.
    web/content/docs/api.mdx · evidence: openapi/primitive-api.yaml, sdk-go/api/oas_operations_gen.go
  • contradicted The GET /v1/sent-emails/{id}/reply endpoint is the awaitReply operation that reports whether a reply has arrived for a sent message.
    web/content/docs/search.mdx · evidence: sdk-go/api/oas_client_gen.go, sdk-go/api/oas_operations_gen.go
  • unverifiable The example code for using the generated API package to set a memory is valid against the current SDK surface.
    sdk-go/README.md · evidence: sdk-go/api/oas_operations_gen.go

This PR also touches evidence for 224 verified claims — no action needed unless behavior changed; the nightly scan re-verifies automatically.

details
  • ✅ The example CLI command for creating an exact route is valid against the current CLI. (web/content/docs/routing.mdxopenapi/primitive-api.codegen.json)
  • ✅ The List payments (ledger) operation uses GET /v1/x402/payments. (web/content/docs/collecting-payments.mdxopenapi/primitive-api.codegen.json)
  • ✅ A Function inbound endpoint is created by binding a route to a deployed JavaScript handler using the CLI command primitive functions:route-set or PUT /v1/functions/{id}/route. (web/content/docs/receiving.mdxopenapi/primitive-api.codegen.json, packages/api-core/src/api/sdk.gen.ts)
  • ✅ The DELETE /v1/memories endpoint accepts a key query parameter to delete a memory. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ The List declined payments operation uses GET /v1/x402/declined-payments. (web/content/docs/collecting-payments.mdxopenapi/primitive-api.yaml)
  • ✅ A PUT to https://api.primitive.dev/v1/functions/{id} with code and sourceMap redeploys an existing Function. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ client.reply(email, ...) derives threading and the Re: subject from the parent message server-side. (sdk-node/README.mdopenapi/primitive-api.yaml)
  • ✅ All credit and checkout requests authenticate with the agent's API key using the header Authorization: Bearer prim_... (web/content/docs/credits.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for creating an exact route bound to a function is valid against the current SDK/API surface. (web/content/docs/routing.mdxopenapi/primitive-api.yaml)
  • ✅ The Create challenge operation uses POST /v1/x402/challenges. (web/content/docs/collecting-payments.mdxopenapi/primitive-api.yaml)
  • ✅ Primitive provides one API for sending outbound mail, receiving inbound mail as signed JSON, and running hosted Functions on incoming messages. (web/content/docs/index.mdxopenapi/primitive-api.yaml)
  • ✅ Resolving a handle is done with GET /registries/{slug}/agents/{handle}. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ Webhook delivery attempts can be replayed from the webhook delivery API. (web/content/docs/receiving.mdxopenapi/primitive-api.yaml)
  • ✅ Outbound mail is sent via POST to https://api.primitive.dev/v1/send-mail. (web/content/docs/sending.mdxopenapi/primitive-api.yaml)
  • ✅ The in_reply_to field takes the Message-ID of the message being replied to. (web/content/docs/sending.mdxopenapi/primitive-api.yaml)
  • ✅ PUT https://api.primitive.dev/v1/functions//route sets the inbound route for a Function. (web/content/docs/quickstart.mdxopenapi/primitive-api.yaml)
  • ✅ The endpoint GET /v1/functions exists. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ A GET to https://api.primitive.dev/v1/emails/{uuid} returns an email. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ When changing the HTTP API contract, openapi/primitive-api.yaml should be updated. (docs/architecture.mdopenapi/primitive-api.yaml)
  • ✅ The HTTP API contract is located at openapi/primitive-api.yaml. (docs/architecture.mdopenapi/primitive-api.yaml)
  • ✅ The example curl command for fetching a thread is valid against the current API surface. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/memories endpoint accepts a key query parameter to retrieve a memory. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ A PUT request to https://api.primitive.dev/v1/functions/{id} with code redeploys the Function. (web/content/docs/functions/first-function.mdxopenapi/primitive-api.yaml)
  • ✅ The Wake API supports POST /v1/wake/authorizations accepting the receiving endpoint id, sender domain, and optionally a single address and a list of allowed commands, and GET /v1/wake/authorizations. (web/content/docs/wake.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/emails endpoint's wait parameter is a long-poll hold in seconds from 0 to 30 with default 0, holds the request open until a newer email arrives or the timeout elapses, and requires since. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ The current and only supported major version of the Primitive REST API is v1, served at https://api.primitive.dev/v1. (web/content/docs/versioning.mdxopenapi/primitive-api.yaml)
  • ✅ The POST /v1/domains//verify endpoint verifies a domain. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ Actual storage usage is reported by GET /v1/account/storage, and if its quota_mb differs from storage_mb for the account, the user should contact support. (web/content/docs/limits.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/emails endpoint's cursor parameter is a continuation cursor from a previous response's meta.cursor. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ Clients should use meta.cursor equal to null as the end-of-page signal rather than comparing row count to limit. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The credential must be sent in the Authorization header. (web/content/docs/api.mdxopenapi/primitive-api.yaml, sdk-go/api/oas_security_gen.go)
  • ✅ The GET /v1/account/webhook-secret response returns a JSON object with a 'secret' field. (web/content/docs/auth.mdxopenapi/primitive-api.yaml)
  • ✅ A POST to https://api.primitive.dev/v1/org/secrets with key and value creates an org-level secret. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ The Functions REST API authenticates with an Authorization: Bearer header using the PRIMITIVE_API_KEY. (web/content/docs/functions/github-actions.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for testing an endpoint is valid against the current SDK/API surface. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ A GET to https://api.primitive.dev/v1/emails with a limit parameter returns emails. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for deploying a Function via cURL is valid against the current API surface. (web/content/docs/quickstart.mdxopenapi/primitive-api.yaml)
  • ✅ All Agent Registry API endpoints are under the base URL https://api.primitive.dev/v1. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ Every authenticated request to https://api.primitive.dev/v1 carries a bearer credential in the Authorization header. (web/content/docs/auth.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for deleting a memory via DELETE /v1/memories?key= is valid against the current API. (web/content/docs/memories.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for searching emails is valid against the current API surface. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ Content deletion is done by the user via content discard and is irreversible. (web/content/docs/limits.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/emails endpoint's date_from and date_to parameters are inclusive ISO 8601 bounds on created_at. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/emails endpoint's status parameter accepts one of pending, accepted, completed, or rejected. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ Stored email content can be discarded via POST https://api.primitive.dev/v1/emails//discard-content with a Bearer API key. (web/content/docs/receiving.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for approving a pending request via POST /v1/registries/my-registry/requests/ is valid against the current API surface. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ The Primitive REST API is served under the base URL https://api.primitive.dev/v1. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The endpoint POST /v1/functions/{id}/secrets exists. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ The 'primitive filters' command group provides allow/block filter CRUD. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/emails response carries data (the page of emails) and meta containing total, limit, and next cursor, which is null when the end is reached. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/emails endpoint's domain_id parameter restricts results to one verified domain. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/emails endpoint accepts a limit query parameter, and GET /v1/emails/ retrieves a single email. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ The first to entry is the primary recipient and fills the scalar to_address field in list responses. (web/content/docs/sending.mdxopenapi/primitive-api.yaml)
  • ✅ The email.id field is the stored email id and can be used with REST endpoints such as /v1/emails/{id}, /v1/emails/{id}/replay, and /v1/emails/{id}/reply. (web/content/docs/webhook-payload.mdxopenapi/primitive-api.yaml)
  • ✅ Billing and organization settings require an owner or admin role and are performed in the dashboard rather than the REST API. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The example CLI code for resolving a handle with 'primitive registries resolve' is valid against the current CLI. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ A GET to https://api.primitive.dev/v1/sent-emails/{uuid} returns a sent email. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ The Register payout address operation uses POST /v1/x402/payout-addresses. (web/content/docs/collecting-payments.mdxopenapi/primitive-api.yaml)
  • ✅ The Payments (x402) area provides POST/GET /x402/payout-addresses, POST /x402/challenges, POST /x402/email-challenges, GET /x402/challenges/{id}, POST /x402/challenges/{id}/pay, GET /x402/payments, GET /x402/declined-payments, and GET/PUT /x402/spend-policy endpoints. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for getting a memory via GET /v1/memories?key= is valid against the current API. (web/content/docs/memories.mdxopenapi/primitive-api.yaml)
  • ✅ The custom domain type requires publishing the DNS records Primitive shows you. (web/content/docs/domains.mdxopenapi/primitive-api.yaml)
  • ✅ All memory REST endpoints live under https://api.primitive.dev/v1 and use the standard Primitive bearer auth header. (web/content/docs/memories.mdxopenapi/primitive-api.yaml)
  • ✅ The Primitive API base URL is https://api.primitive.dev/v1. (web/content/docs/connectors.mdxopenapi/primitive-api.yaml)
  • ✅ The CLI command primitive sending:get-send-permissions inspects active send rules. (web/content/docs/sending.mdxopenapi/primitive-api.yaml, packages/api-core/src/openapi/operations.generated.ts, sdk-go/api/oas_operations_gen.go)
  • ✅ The example curl command for tailing the inbox with since and wait is valid against the current API surface. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ A POST to https://api.primitive.dev/v1/functions/{id}/secrets with key and value creates a Function secret. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for reading effective limits from GET /v1/account is valid against the current SDK/API surface. (web/content/docs/limits.mdxopenapi/primitive-api.yaml)
  • ✅ REST API fields use snake_case naming. (web/content/docs/sending.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/x402/payments endpoint enumerates an org's x402 payments. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for reading the credit balance is valid against the current SDK/API surface. (web/content/docs/credits.mdxopenapi/primitive-api.yaml)
  • ✅ The GET https://api.primitive.dev/v1/account endpoint returns account info when given a Bearer API key. (web/content/docs/quickstart.mdxopenapi/primitive-api.yaml)
  • ✅ Primitive provides a REST API with stable HTTP endpoints under https://api.primitive.dev/v1. (web/content/docs/index.mdxopenapi/primitive-api.yaml)
  • ✅ The Routing area provides GET/POST /routes, POST /routes/reorder, POST /routes/simulate, and PATCH/DELETE /routes/{id} endpoints. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ Deprecated operations or fields are marked deprecated: true in the OpenAPI spec with a description calling out the replacement. (web/content/docs/versioning.mdxopenapi/primitive-api.yaml)
  • ✅ The cURL example for sending an attachment is valid against the current API surface. (web/content/docs/sending.mdxopenapi/primitive-api.yaml)
  • ✅ The 'primitive payments get-challenge' command accepts an '--id' flag. (cli-node/README.mdopenapi/primitive-api.yaml)
  • ✅ The example code for listing routes in evaluation order is valid against the current SDK/API surface. (web/content/docs/routing.mdxopenapi/primitive-api.yaml)
  • ✅ The full-fidelity record for a send can be read from GET /v1/sent-emails/{id} using the same id. (web/content/docs/simple-email.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for listing the inbox is valid against the current API surface. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ GET https://api.primitive.dev/v1/emails supports a limit query parameter to list emails. (web/content/docs/quickstart.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for listing active endpoints, patching an endpoint, and deleting an endpoint is valid against the current SDK/API surface. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ The 'primitive deliveries replay' command accepts an '--id' flag. (cli-node/README.mdopenapi/primitive-api.yaml)
  • ✅ The cURL example for creating an email challenge is valid against the current API surface. (web/content/docs/x402-over-email.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for setting a memory via PUT /v1/memories is valid against the current API. (web/content/docs/memories.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for listing webhook deliveries is valid against the current SDK/API surface. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ Fine-grained per-key scopes such as send-only or read-only keys are on the roadmap and not yet available. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The Endpoints area provides webhook endpoint CRUD via GET/POST /endpoints and PATCH/DELETE /endpoints/{id} plus POST /endpoints/{id}/test. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for accessing the v1 account endpoint with a bearer token is valid against the current API surface. (web/content/docs/versioning.mdxopenapi/primitive-api.yaml)
  • ✅ Defining an agent is a global operation using POST /v1/agents and is not scoped to any registry. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ The cursor query parameter for listing deliveries is an opaque cursor from the previous page's meta.cursor used for pagination. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ v2 will be announced at least 6 months before v1 is sunset, with the v1 sunset date published in the OpenAPI spec via info.x-sunset-date and on the status page. (web/content/docs/versioning.mdxopenapi/primitive-api.yaml)
  • ✅ Stored mail can be filtered via search by sender, recipient, subject, body text, date, or processing state. (web/content/docs/receiving.mdxopenapi/primitive-api.yaml)
  • ✅ POST https://api.primitive.dev/v1/emails//reply replies to an inbound email with a body_text field. (web/content/docs/quickstart.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for replaying a delivery is valid against the current SDK/API surface. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ The POST /v1/functions endpoint accepts a JSON body with name and code fields. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ The HTTP API contract is located in the openapi/ directory. (docs/architecture.mdopenapi/primitive-api.yaml)
  • ✅ The Primitive API uses Bearer authentication with either an organization-scoped API key or an OAuth access token. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The endpoint POST /v1/org/secrets exists. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for fetching a conversation is valid against the current API surface. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/emails endpoint's since parameter is a forward-tail cursor returning only emails strictly newer than the cursor, oldest-first, and is mutually exclusive with cursor. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ A POST request to https://api.primitive.dev/v1/functions/{id}/test triggers a test email for the Function. (web/content/docs/functions/first-function.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for scanning a fixed window oldest-first is valid against the current API surface. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ When Wait is true, the call returns the first downstream SMTP outcome or times out at WaitTimeoutMs which defaults to 30000 ms. (sdk-go/README.mdopenapi/primitive-api.yaml)
  • ✅ The example code for calling the account endpoint with a Bearer token is valid against the current API surface. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/threads/{id} endpoint returns thread metadata plus all inbound and outbound messages interleaved oldest-first without bodies. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ All routing endpoints live under the base URL https://api.primitive.dev/v1. (web/content/docs/routing.mdxopenapi/primitive-api.yaml)
  • ✅ POST https://api.primitive.dev/v1/send-mail sends an email with a JSON body. (web/content/docs/quickstart.mdxopenapi/primitive-api.yaml)
  • ✅ An inbound email can be replayed using the CLI command primitive emails:replay-email-webhooks --id . (web/content/docs/faq.mdxopenapi/primitive-api.yaml)
  • ✅ Some capabilities are enabled per organization and appear in the entitlements array from GET /v1/account. (web/content/docs/limits.mdxopenapi/primitive-api.yaml)
  • ✅ To use branded mail, users can add their own domain and publish the DNS records Primitive shows them. (web/content/docs/index.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/account/storage endpoint reports how much of the stored-email quota is in use. (web/content/docs/limits.mdxopenapi/primitive-api.yaml)
  • ✅ Getting a registry's metadata is done with GET /registries/{slug}. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ The Inbound emails area provides GET /emails, GET /emails/search, GET /emails/{id}, GET /emails/{id}/conversation, and raw/attachments/discard/replay/reply actions. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for reading storage usage from GET /v1/account/storage is valid against the current SDK/API surface. (web/content/docs/limits.mdxopenapi/primitive-api.yaml)
  • ✅ Replying via the API uses POST https://api.primitive.dev/v1/emails//reply. (web/content/docs/sending.mdxopenapi/primitive-api.yaml)
  • ✅ The DeliveryStatus value 'deferred' means a temporary failure and the receiving MTA may retry. (sdk-go/README.mdopenapi/primitive-api.yaml)
  • ✅ The API contract version is fixed at v1 until or unless a v2 ships. (web/content/docs/versioning.mdxopenapi/primitive-api.yaml)
  • ✅ All endpoints live under the base URL https://api.primitive.dev/v1 and authenticate with a bearer API key. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ Listing your registries is done with GET /registries or the 'primitive registries list' CLI command. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/domains//zone-file endpoint returns a domain's zone file. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ The example JSON response for GET /v1/account/storage is valid against the current API surface. (web/content/docs/limits.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl request to POST /v1/x402/challenges for creating a challenge is valid against the current API surface. (web/content/docs/collecting-payments.mdxopenapi/primitive-api.yaml)
  • ✅ The endpoint PUT /v1/functions/{id} exists. (web/content/docs/functions.mdxopenapi/primitive-api.yaml, sdk-go/api/oas_server_gen.go)
  • ✅ A POST to https://api.primitive.dev/v1/functions with name, code, and sourceMap creates a Function. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ The limit query parameter for listing deliveries sets page size between 1 and 100 with a default of 50. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ The POST /v1/domains endpoint accepts a JSON body with a domain field. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ An inbound email can be replayed via POST https://api.primitive.dev/v1/emails//replay with a Bearer API key. (web/content/docs/receiving.mdxopenapi/primitive-api.yaml)
  • ✅ The endpoint DELETE /v1/functions/{id}/secrets/{key} exists. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ The redeploy PUT request body accepts a JSON object with code and sourceMap fields. (web/content/docs/functions/github-actions.mdxopenapi/primitive-api.yaml)
  • ✅ Each thread entry carries a direction and an id, and the body is fetched on demand with GET /v1/emails/{id} for inbound or GET /v1/sent-emails/{id} for outbound. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ 'domains add' returns the exact DNS records to publish. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for retrieving the webhook secret via GET /v1/account/webhook-secret is valid against the current API surface. (web/content/docs/auth.mdxopenapi/primitive-api.yaml)
  • ✅ The Account area provides GET/PATCH /account, GET /account/storage, GET /account/webhook-secret, and POST /account/webhook-secret/rotate endpoints. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ A Function can be redeployed by calling the REST API directly with curl and jq. (web/content/docs/functions/github-actions.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for creating a blocklist filter org-wide is valid against the current SDK/API surface. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ The Primitive REST API uses URL path versioning. (web/content/docs/versioning.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/send-permissions endpoint returns send permissions when authorized with a bearer API key. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ The date_from and date_to query parameters for listing deliveries are ISO 8601 timestamps bounding created_at. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ Clients should branch on the stable error.code values rather than human-readable error messages. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ Fine-grained per-scope OAuth grants that narrow a token to a subset of operations are not yet exposed. (web/content/docs/api.mdxopenapi/primitive-api.yaml, sdk-go/api/oas_security_gen.go)
  • ✅ POST https://api.primitive.dev/v1/functions creates a Function with a JSON body containing name and code. (web/content/docs/quickstart.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl/jq script for redeploying via the REST API is valid. (web/content/docs/functions/github-actions.mdxopenapi/primitive-api.yaml)
  • ✅ An account's effective limits are returned by the API. (web/content/docs/limits.mdxopenapi/primitive-api.yaml)
  • ✅ The endpoint POST /v1/functions/{id}/test exists. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ A GET to https://api.primitive.dev/v1/sent-emails with a limit parameter returns sent emails. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ Active send rules can be inspected via GET https://api.primitive.dev/v1/send-permissions. (web/content/docs/sending.mdxopenapi/primitive-api.yaml)
  • ✅ The shipped OpenAPI spec is canonical at https://api.primitive.dev/v1/openapi, also served as /openapi.json and /openapi.yaml, and carries an info.version field. (web/content/docs/versioning.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for creating an HTTP endpoint is valid against the current SDK/API surface. (web/content/docs/endpoints.mdxopenapi/primitive-api.yaml)
  • ✅ The Threads area provides GET /threads/{id} which returns the full message chain an inbound email belongs to. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The function-specific endpoints include GET/POST /v1/functions, GET/PUT/DELETE /v1/functions/{id}, POST /v1/functions/{id}/test, GET /v1/functions/{id}/logs, GET/POST /v1/functions/{id}/secrets, and PUT/DELETE /v1/functions/{id}/secrets/{key}. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ To move to a custom domain, you add a domain in the dashboard, publish the DNS records, and wait for verification. (web/content/docs/managed-inbox.mdxopenapi/primitive-api.yaml)
  • ✅ Approving or rejecting a request is done with POST /registries/{slug}/requests/{id} or the 'primitive registries decide' CLI command. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ The example JSON response for GET /v1/account is valid against the current API surface. (web/content/docs/limits.mdxopenapi/primitive-api.yaml)
  • ✅ Successful API responses use an envelope with success true, a data object, and a meta object containing total, limit, and cursor. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The cURL example for sending mail is valid against the current API surface. (web/content/docs/sending.mdxopenapi/primitive-api.yaml)
  • ✅ The primitive sending:list-sent-emails CLI command accepts a --limit option. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ A POST to https://api.primitive.dev/v1/functions/{id}/test fires a test invocation. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ A DELETE to https://api.primitive.dev/v1/functions/{id}/secrets/{key} deletes a Function secret. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ PUT /v1/functions/{id} replaces function code and optionally accepts a sourceMap field for source-mapped logs. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ GET /v1/functions/routing-topology returns the org's Function routing map showing which Functions are wired to which inbound domains. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ The info.version field tracks the spec's editorial revisions rather than the API contract. (web/content/docs/versioning.mdxopenapi/primitive-api.yaml)
  • ✅ The REST search cursor parameter is a continuation cursor from meta.cursor. (web/content/docs/memories.mdxopenapi/primitive-api.yaml)
  • ✅ Inbound emails can be listed via GET https://api.primitive.dev/v1/emails with a Bearer API key, and a single email fetched via GET https://api.primitive.dev/v1/emails/. (web/content/docs/receiving.mdxopenapi/primitive-api.yaml)
  • ✅ Updating a registry is done with PATCH /registries/{slug} or the 'primitive registries update' CLI command. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/emails/search endpoint is the structured query endpoint accepting dedicated filter parameters, a full-text query (q), or both. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ The POST /v1/functions//test endpoint tests a function, and GET /v1/functions//logs returns its logs. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ Registering a payout address uses POST /v1/x402/payout-addresses. (web/content/docs/x402-over-email.mdxopenapi/primitive-api.yaml)
  • ✅ The Update spend policy operation uses PUT /v1/x402/spend-policy. (web/content/docs/collecting-payments.mdxopenapi/primitive-api.yaml, sdk-go/api/oas_operations_gen.go)
  • ✅ GET https://api.primitive.dev/v1/emails/ retrieves a specific email. (web/content/docs/quickstart.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl request to POST https://api.primitive.dev/v1/send-mail is valid against the current API surface. (web/content/docs/managed-inbox.mdxopenapi/primitive-api.yaml, packages/api-core/src/api/sdk.gen.ts)
  • ✅ An inbound email can be replayed via the POST /v1/emails/{id}/replay API endpoint. (web/content/docs/faq.mdxopenapi/primitive-api.yaml)
  • ✅ The DeliveryStatus value 'wait_timeout' means no outcome was observed in time. (sdk-go/README.mdopenapi/primitive-api.yaml)
  • ✅ The combined search DSL example curl command is valid against the current API surface. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ The example curl command for rotating the webhook secret via POST /v1/account/webhook-secret/rotate is valid against the current API surface. (web/content/docs/auth.mdxopenapi/primitive-api.yaml)
  • ✅ The GET /v1/account endpoint returns account context when authorized with a bearer API key. (web/content/docs/cli.mdxopenapi/primitive-api.yaml)
  • ✅ A GET request to https://api.primitive.dev/v1/functions/{id}/logs returns Function logs. (web/content/docs/functions/first-function.mdxopenapi/primitive-api.yaml)
  • ✅ List endpoints use cursor pagination via limit and cursor query parameters. (web/content/docs/api.mdxopenapi/primitive-api.yaml)
  • ✅ The REST endpoint to redeploy a Function is PUT https://api.primitive.dev/v1/functions/{id}. (web/content/docs/functions/github-actions.mdxopenapi/primitive-api.yaml, packages/api-core/src/api/sdk.gen.ts)
  • ✅ The GET /v1/emails endpoint's limit parameter is page size from 1 to 100 with a default of 50. (web/content/docs/search.mdxopenapi/primitive-api.yaml)
  • ✅ The 'primitive payments create-email-challenge' command takes '--amount' in token base units only and has no '--amount-usdc' flag. (cli-node/README.mdopenapi/primitive-api.yaml)
  • ✅ The base URL for the Simple Email surface is https://api.primitive.dev/v1/simple-email. (web/content/docs/simple-email.mdxopenapi/primitive-api.yaml)
  • ✅ The endpoint POST /v1/functions exists. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ After publishing DNS, verification can be triggered by clicking Verify in the dashboard or by calling the domains API. (web/content/docs/domains.mdxopenapi/primitive-api.yaml)
  • ✅ The endpoint DELETE /v1/functions/{id} exists. (web/content/docs/functions.mdxopenapi/primitive-api.yaml)
  • ✅ To page forward, set the cursor query parameter to the meta.cursor value from the previous response, which is non-null while more pages remain. (web/content/docs/agent-registry.mdxopenapi/primitive-api.yaml)
  • ✅ A POST request to https://api.primitive.dev/v1/functions/{id}/secrets with key and value sets a Function secret. (web/content/docs/functions/first-function.mdxopenapi/primitive-api.yaml)
  • ✅ The example code for the generated API client using PrimitiveApiClient and getAccount is valid against the current SDK/API surface. (sdk-node/README.mdpackages/api-core/src/api/index.ts, packages/api-core/src/api/sdk.gen.ts)
  • ✅ The raw generated operations setMemory, getMemory, searchMemories, and deleteMemory are exported from @primitivedotdev/sdk/api. (sdk-node/README.mdpackages/api-core/src/api/index.ts)
  • ✅ The SDKs expose getChallenge(id) in Node, get_challenge(id) in Python, and GetChallenge(ctx, id) in Go to read a challenge's status. (web/content/docs/collecting-payments.mdxpackages/api-core/src/api/sdk.gen.ts, sdk-go/api/oas_client_gen.go)
  • ✅ The Node SDK's generated artifacts are a webhook schema module, TypeScript types, validator module, generated API client, and generated OpenAPI document export. (docs/architecture.mdpackages/api-core/src/api/sdk.gen.ts)
  • ✅ An agent can provision its own Primitive identity (a managed inbox to send and receive) with no API key and no human review. (web/content/docs/skills.mdxpackages/api-core/src/api/sdk.gen.ts)
  • ✅ The generated SDK clients expose lower-level OpenAPI operation ids setMemory, getMemory, deleteMemory, and searchMemories. (web/content/docs/memories.mdxpackages/api-core/src/api/sdk.gen.ts)
  • ✅ The returned Function id is used for redeploy, test, logs, secrets, and delete operations. (web/content/docs/functions.mdxpackages/api-core/src/api/sdk.gen.ts)
  • ✅ Every routing operation is available as a primitive routes CLI verb generated from the same API spec. (web/content/docs/routing.mdxpackages/api-core/src/api/sdk.gen.ts)
  • ✅ The primitive functions:route-set command accepts --fallback or --domain <domain-id> and is backed by PUT /v1/functions/{id}/route. (web/content/docs/functions.mdxpackages/api-core/src/api/sdk.gen.ts)
  • ✅ The only human touch in agent signup is one email-verification code, which the agent can ask the user for inline. (web/content/docs/skills.mdxpackages/api-core/src/api/sdk.gen.ts)
  • ✅ The start-agent-signup command's output includes a signup_token, which is a session handle rather than a credential. (web/content/docs/skills.mdxpackages/api-core/src/api/types.gen.ts)
  • ✅ A deliveryStatus of wait_timeout means no outcome was observed in time. (sdk-node/README.mdpackages/api-core/src/api/types.gen.ts)
  • ✅ A wake grant requires a sender domain that the wake must come from. (web/content/docs/wake.mdxpackages/api-core/src/api/types.gen.ts)
  • ✅ A memory record includes created_at and updated_at fields for creation and last write timestamps. (web/content/docs/memories.mdxpackages/api-core/src/api/types.gen.ts)
  • ✅ In the SDK, function-scoped writes pass scope: { type: 'function', id: '' }. (web/content/docs/memories.mdxpackages/api-core/src/api/types.gen.ts)
  • ✅ A memory record includes a key field that is the caller-defined key. (web/content/docs/memories.mdxpackages/api-core/src/api/types.gen.ts)
  • ✅ @primitivedotdev/sdk/openapi exports the OpenAPI document and the operation manifest as JSON. (sdk-node/README.mdpackages/api-core/src/openapi/openapi.generated.ts, packages/api-core/src/openapi/operations.generated.ts)
  • ✅ The command 'primitive agent start-agent-signup --email --terms-accepted' starts agent signup. (web/content/docs/skills.mdxpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The example CLI code for deciding a request with 'primitive registries decide' is valid against the current CLI. (web/content/docs/agent-registry.mdxpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The command 'primitive agent verify-agent-signup --verification-code --signup-token ' completes signup. (web/content/docs/skills.mdxpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The storage_mb field represents the plan's stored-email storage allowance in MB. (web/content/docs/limits.mdxpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The 'primitive payments get-challenge' command reads a challenge by id including status and settle tx. (web/content/docs/cli.mdxpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The command 'primitive agent resend-agent-signup-verification --signup-token ' reissues the verification code. (web/content/docs/skills.mdxpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The example CLI code for defining an agent with 'primitive registries define' is valid against the current CLI. (web/content/docs/agent-registry.mdxpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The example CLI code for publishing an agent with 'primitive registries publish' is valid against the current CLI. (web/content/docs/agent-registry.mdxpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The primitive describe command outputs the inlined request/response schema of a single operation including per-field descriptions. (sdk-node/README.mdpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The 'primitive emails get' command accepts an '--id' flag. (cli-node/README.mdpackages/api-core/src/openapi/operations.generated.ts)
  • ✅ The Filters area provides allow/block filter CRUD via GET/POST /filters and PATCH/DELETE /filters/{id}. (web/content/docs/api.mdxsdk-go/api/oas_client_gen.go)
  • ✅ Creating a registry is done with POST /registries or the 'primitive registries create' CLI command. (web/content/docs/agent-registry.mdxsdk-go/api/oas_client_gen.go)
  • ✅ primitiveapi client has a SetMemory method accepting a context, a *primitiveapi.SetMemoryInput with Key and Value fields, and a primitiveapi.SetMemoryParams. (sdk-go/README.mdsdk-go/api/oas_client_gen.go, sdk-go/api/oas_json_gen.go, sdk-go/api/oas_operations_gen.go)
  • ✅ A canceled context surfaces as context.Canceled and a deadline exceeded surfaces as context.DeadlineExceeded. (sdk-go/README.mdsdk-go/api/oas_client_gen.go)
  • ✅ Function scaffolding is local project generation and has no REST endpoint. (web/content/docs/quickstart.mdxsdk-go/api/oas_operations_gen.go)
  • ✅ The CLI example for creating an email challenge is valid against the current CLI surface. (web/content/docs/x402-over-email.mdxsdk-go/api/oas_operations_gen.go)
  • ✅ There is no REST endpoint for creating scaffold files locally; the REST equivalent begins at deployment of the built bundle. (web/content/docs/functions/first-function.mdxsdk-go/api/oas_operations_gen.go)
  • ✅ The CLI command primitive emails:replay-email-webhooks --id replays an inbound email's webhooks. (web/content/docs/receiving.mdxsdk-go/api/oas_operations_gen.go)
  • ✅ primitive.SendAttachment has Filename and ContentBase64 fields, and ReplyParams has an Attachments field of type []primitive.SendAttachment. (sdk-go/README.mdsdk-go/api/oas_schemas_gen.go)
  • ✅ primitiveapi exposes a NewStringMemoryJsonValue constructor function. (sdk-go/README.mdsdk-go/api/oas_schemas_gen.go)
  • ✅ The wire format for authenticating with an API key is 'Authorization: Bearer prim_...'. (web/content/docs/auth.mdxsdk-go/api/oas_security_gen.go)

@greptile-apps

greptile-apps Bot commented Aug 6, 2026

Copy link
Copy Markdown

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported TypeScript reply-type widening has been corrected.

Important Files Changed

Filename Overview
openapi/primitive-api.yaml Defines the new endpoint and uses a nullable referenced schema that generates the intended reply type.
packages/api-core/src/api/types.gen.ts The regenerated AwaitReplyResult.reply is correctly typed as `ReplyEmail
packages/api-core/src/api/sdk.gen.ts Adds the generated TypeScript awaitReply operation with the expected path and parameters.
sdk-python/src/primitive/api/api/sending/await_reply.py Adds the generated Python client operation for the new endpoint.
sdk-go/api/oas_schemas_gen.go Adds generated Go schemas for the await-reply response and compact reply object.

Reviews (2): Last reviewed commit: "Type the awaitReply no-reply branch as a..." | Re-trigger Greptile

Comment thread packages/api-core/src/api/types.gen.ts Outdated
The generator maps a bare null type in a union to unknown, collapsing
the TypeScript result to unknown; the allOf-plus-nullable idiom the
spec already uses elsewhere generates ReplyEmail or null in all three
languages.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@poiley
poiley merged commit 3ad3b1e into main Aug 6, 2026
6 of 7 checks passed
@poiley
poiley deleted the spec-await-reply branch August 6, 2026 20:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant