Publisher guide

Fitting your API to Txpass

Txpass is a generic access rail: it works for any API publisher. It does not change your API and does not special-case any publisher. This page covers how to shape what you publish so buyer agents (txpass-agent) can call your API without guessing. ImprintAI appears only as a worked example, in boxed sections.

If your API and Txpass don't fit somewhere, fit your API's description to Txpass. Don't expect a Txpass special case. The levers you control are listed below.

1. Describe every route agents should call (examples)

Agents learn your API from txpass-agent describe. It reads the docs_url and examples you save on /publisher (owner route save, or a config agent with the docs capability). You get up to 10 examples. Each example has:

KeyMeaning
idShort id (a-z0-9-); agents run txpass-agent request --example <id>.
method, pathMethod and path pattern on your API origin, e.g. /v1/jobs/:jobId.
descriptionOne sentence: what the call does and what comes back.
bodyMinimal JSON body that works (≤ 4 KiB). Omit for GET/HEAD and for uploads.
fields[]{ name, type, required, description }; list every field the call needs.
notes[]Side effects, cost, error shapes, what to poll.

Your public docs site is not enough. Agents only see what describe returns. If a call needs a field, put it in that example's fields, even if your own docs already list it.

File uploads (multipart)

A field whose type starts with file marks the route as multipart/form-data. Declare the MIME type in brackets so the agent's example command uses the right file extension:

{ "id": "upload", "method": "POST", "path": "/v1/documents",
  "description": "Upload a document; returns its id.",
  "fields": [
    { "name": "document", "type": "file (application/pdf)", "required": true },
    { "name": "title", "type": "string", "required": true }
  ] }

describe then prints txpass-agent request POST /v1/documents --file document=./document.pdf --field title=TITLE. Txpass does not guess from field names: a file type with no declared MIME type becomes ./<field>.bin.

Multi-step APIs (data from an earlier call)

If one call needs a value returned by an earlier call (a job id, a hash, a transaction id, a record id), document both ends:

  1. In the first example's notes, say which response field or header carries the value.
  2. In the second example's fields, list that value with a description that names its source, e.g. "description": "record_id from the create answer".

2. Response headers agents will see

From agent 0.1.9, txpass-agent request passes your response headers to the caller, with and without --output. That includes custom metadata such as X-<YourCo>-Receipt-Id or X-<YourCo>-Status. No header name is special-cased per publisher.

Dropped:

  • set-cookie, set-cookie2, cookie, authorization, proxy-authorization, proxy-authenticate, www-authenticate;
  • any header whose name contains txpass, session, token, bearer, secret, api-key/apikey, password, credential, auth, cookie or signature-key.

Caps: 50 headers, 1 KiB per value (longer values are cut off), 16 KiB in total. Output is still redacted.

So: put agent-useful results in plainly named headers (or in the body). Don't use names that look like credentials, and keep values short.

3. Size limits

These are agent-side defaults; the operator can change them in config.json limits:

LimitDefaultApplies to
max_request_bytes64 KiBJSON bodies (--json, --example)
max_upload_bytes20 MiBmultipart bodies (--file / --field)
max_response_bytes256 KiBresponse read limit; --output writes nothing if the body is larger

If your API takes larger uploads, say so in the example notes so operators know to raise max_upload_bytes. --output writes the body only for 2xx responses.

4. Payment (402) and free auto-enroll

A buyer with no live entitlement gets 402 from the facilitator's session mint. Your product policy decides:

  • on_new_identity: reject: the buyer must buy a plan first (production default).
  • on_new_identity: auto_enroll + auto_enroll_plan: free + free quotas: first-time buyers get a facilitator-issued free entitlement. This also applies to agents acting under an approved owner policy: the policy owner is enrolled on the free plan when their agent mints its first session.

See Publisher onboarding for the policy fields.

5. Owner keys, buyer keys and --allow-new-issuer

  • Owner keys own a product on /publisher. They approve config agents.
  • Buyer keys hold entitlements and approve buyer agents on /account/connect.
  • These are often different keys. An agent pins the first owner/issuer key it trusted (expected_issuer). If a later approval is signed by another key, the agent stops with issuer_mismatch and saves nothing. The approval page shows which owner key is signing. If that key really is the right owner, re-run the command with --allow-new-issuer. Txpass never relaxes this check silently.

6. Config agents (publisher-connect)

txpass-agent publisher-connect <product> asks an owner to grant a coding agent limited rights to configure the product on Txpass (not to call your API). Capabilities:

CapabilityLets the agent
stagingset / clear the staging origin and trial routes
return_originsedit the sign-in popup return allowlist
routes_copyedit route labels, groups, kind, recommended, description
api_originsedit registered API base hosts
docsedit docs_url and examples (section 1)

Route-copy precondition: routes_copy, api_origins and docs edit your saved product copy. A built-in product has no saved copy until an owner saves route copy once on /publisher. Until then those writes return 403 config_capability_denied. Agents cannot create the first copy because that also sets the owner list. staging and return_origins work immediately. The grant page warns about this.

Re-approval: running publisher-connect again for an agent that already has a grant on the product just works. The approval page shows "Replaces existing grant (caps X → Y)". When the owner signs, the old grant is revoked and the new one issued in one step, and the change is recorded in the product's change log. Capabilities only change through the owner's signature.

Worked example: ImprintAI (illustrative; Imprint is one publisher on the rail, not the model)

  • Create (POST /api/imprint, JSON) returns a txid. A second, multipart call takes an image file plus that txid (and a canonical_pixel_hash). The fit is: declare the upload as { "name": "image", "type": "file (image/png)" }, and list txid / canonical_pixel_hash in its fields with descriptions naming where they come from.
  • Imprint returns metadata headers (X-Imprint-Txid, X-Imprint-C2pa-Status). They pass through like any other publisher header because the names are plain and the values short.