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:
| Key | Meaning |
|---|---|
id | Short id (a-z0-9-); agents run txpass-agent request --example <id>. |
method, path | Method and path pattern on your API origin, e.g. /v1/jobs/:jobId. |
description | One sentence: what the call does and what comes back. |
body | Minimal 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:
- In the first example's
notes, say which response field or header carries the value. - In the second example's
fields, list that value with adescriptionthat 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,cookieorsignature-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:
| Limit | Default | Applies to |
|---|---|---|
max_request_bytes | 64 KiB | JSON bodies (--json, --example) |
max_upload_bytes | 20 MiB | multipart bodies (--file / --field) |
max_response_bytes | 256 KiB | response 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 withissuer_mismatchand 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:
| Capability | Lets the agent |
|---|---|
staging | set / clear the staging origin and trial routes |
return_origins | edit the sign-in popup return allowlist |
routes_copy | edit route labels, groups, kind, recommended, description |
api_origins | edit registered API base hosts |
docs | edit 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 atxid. A second, multipart call takes animagefile plus thattxid(and acanonical_pixel_hash). The fit is: declare the upload as{ "name": "image", "type": "file (image/png)" }, and listtxid/canonical_pixel_hashin itsfieldswith 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.