Trusted agent verification
Understand what verification establishes
Trusted agent verification helps your service recognize requests signed by a trusted agent. The signature protects the signed parts of the request against modification. Your service still decides what the caller can access and checks payment when the resource requires it.
Visa Trusted Agent Protocol (TAP) carries that signature in HTTP headers. InFlow’s SDKs verify the agent-recognition profile supported by InFlow: a single sig2 Ed25519 signature covering the method, destination host, path and query, plus the body digest and content type when a body is supplied.
The result identifies the signing key and includes the signed intent, browse or pay. A pay intent describes the request’s purpose; it does not prove payment or the buyer’s approval. This verification does not process Visa consumer-recognition objects or payment containers.
Use TAP when your service needs to distinguish requests signed by trusted agents from other traffic. Decide which routes require that recognition. Installing a verifier does not make TAP mandatory across your application or change your existing payment routes.
Add a verifier
All four InFlow SDKs provide seller-side verification. The verifier needs no InFlow account or API key. The default configuration retrieves public verification keys from Visa; it does not require you to obtain an agent’s private signing key.
Create one verifier when your application starts and reuse it across requests. The following fragments show installation and the verification call for each language. They are not complete web servers: your framework must supply the original request values described below and handle verification errors before continuing.
go get github.com/inflowpayai/inflow-go
package agentcheck
import (
"context"
tap "github.com/inflowpayai/inflow-go/tap/seller"
)
func VerifyAgent(ctx context.Context, verifier *tap.Verifier,
request tap.Request) (tap.Facts, error) {
return verifier.Verify(ctx, request)
}Create tap.New(tap.Options{}) once at startup. Pass that verifier and the HTTP request’s context to the helper. Return a failed verification to your HTTP error handler; do not call the protected handler after an error. The Go HTTP example shows request extraction and response handling.
npm install @inflowpayai/tap-seller
import {
createTapVerifier, type TapRequest,
} from '@inflowpayai/tap-seller';
const verifier = createTapVerifier();
export async function verifyAgent(request: TapRequest) {
return verifier.verify(request);
}The module-level verifier is shared by requests. Supply a TapRequest with the method, absolute URL, headers and optional body bytes. Await the result and handle rejection before calling your protected handler. This package uses Node.js cryptography; see the Node.js package guide for middleware and custom stores.
pip install 'inflowpay[tap]'
from inflowpay.tap.seller import (
TapRequest, TapVerificationFacts, TapVerifier,
)
async def verify_agent(
verifier: TapVerifier, request: TapRequest,
) -> TapVerificationFacts:
return await verifier.verify(request)Install the tap extra. Create TapVerifier() at application startup, pass it to handlers, and call await verifier.aclose() at shutdown. An application-lifetime asynchronous context manager is also supported. Do not create or close the verifier inside each request. See the Python examples for server lifecycle integration.
cargo add inflow-tap-seller
use inflow_tap_seller::{
Error, Request, VerifiedFacts, Verifier,
};
pub async fn verify_agent(
verifier: &Verifier, request: &Request,
) -> Result<VerifiedFacts, Error> {
verifier.verify(request).await
}At startup, call Verifier::new with VerifierOptions::default(), handle any construction error, and share the verifier with handlers. The default key resolver uses your application’s Tokio runtime. Construct Request from the method, absolute URL, headers and optional body bytes; Request::new accepts raw header pairs. See the Rust package guide for the full interface.
Successful verification returns the signing key identifier, intent, nonce, signature timestamps and covered request components. Use those facts for your agent-recognition policy. They are not a customer account or a payment receipt.
Preserve the signed request
The verifier checks the request the agent signed, so pass the original values from your web server. For example, parsing a JSON body and then serializing the same data with different whitespace changes the bytes and can invalidate its digest. Capture the body before parsing it, apply your normal request-size limit, and retain those bytes for verification.
Supply the method with its original case, the absolute public URL, the received headers, and the exact body bytes. Preserve the encoded path and query, including parameter order and escaping. Behind a proxy, obtain the public origin from your configured origin or trusted proxy metadata—not arbitrary forwarding headers supplied by a caller.
A missing body and an explicitly supplied empty body are different. An empty body still requires signed Content-Digest and Content-Type fields. Preserve repeated headers rather than silently choosing one value; the verifier rejects ambiguous signed fields.
On a route requiring TAP, only continue after verification succeeds. Reject missing, malformed, invalid or replayed signatures. If verification cannot run because a dependency is unavailable, return an appropriate service error instead of granting access. Keep detailed diagnostics in your controlled server logs, without recording credentials or entire request bodies.
Manage trusted keys and replay protection
The default resolver retrieves public keys from Visa’s key service and caches them. Allow your server to reach that service. A key identifier selects a key from the trusted source; it must not become an arbitrary URL supplied by the caller.
During a key-service outage, the default resolver can use a matching cached key within its permitted maximum age. An unknown key or an unusable cache cannot establish trust. Custom key resolvers must preserve that trust decision rather than accepting a key from the incoming request.
A nonce is a value the signer supplies to distinguish a request from a replay. After checking the signature, the verifier atomically records the signing key and nonce until the signature expires. The built-in memory store protects one process. For multiple workers or servers, configure a shared store whose claim operation succeeds for only the first use of that pair.
Keep the server clock synchronized. This profile accepts signature intervals of at most eight minutes and checks whether the signature is valid when verification starts. Reusing the verifier preserves its cache and replay history; recreating it for each request discards both.
A legitimate retry needs a fresh TAP signature and nonce. That does not mean starting another payment. Keep the payment protocol’s existing retry and duplicate-payment protections; nonce replay protection solves a different problem.
Keep authentication and payment checks
A successful TAP check establishes that the signed request matches a trusted agent key. AEP establishes the caller’s enrollment and service credentials. Your application then applies its permissions, while MPP or x402 handles the payment requirement.
For a route requiring TAP, verify the unchanged request before allowing the protected operation to proceed. Continue through the route’s existing authentication and payment handling. A trusted agent without the required payment still receives a payment challenge; a trusted agent without the required account access still cannot use that account.
Keep settlement timing consistent with your payment integration. TAP does not change when MPP or x402 verifies or settles a payment, nor make a payment-handler response safe to release early. See Deliver paid results for handler execution and delivery rules.
Advertise support and test requests
If your service publishes an ODP Service Document, add TAP to protocols.trust after implementing verification. Merge this field into your existing document; retain its other protocol declarations. Advertising support does not install verification or require TAP on every endpoint.
{
"protocols": {
"trust": [{ "name": "tap" }]
}
}Follow the ODP publishing guide to publish or refresh your Directory listing. For InFlow-issued signatures, the target origin must resolve to one published service advertising TAP. A separate payment origin must also be verified for that service.
To exercise a browse request, use an HTTPS test endpoint that accepts GET without making a purchase. Replace the example URL below with that endpoint. Log in with the CLI’s device flow in the environment you are testing; API-key authentication does not enable TAP signing. The commands below select Sandbox; use the same environment for the Directory listing and CLI session. InFlow must advertise TAP signing capability in that environment.
inflow auth login --sandbox inflow inspect --sandbox 'https://reports.example.com/reports'
Check your server’s verification result for the endpoint request: it should contain a trusted key and browse intent. Inspection may also request discovery documents; identify the target endpoint in your diagnostics. A successful CLI inspection alone is not proof that TAP verification ran. Localhost HTTP requests are intentionally unsigned, and the CLI can send unsigned requests when signing is unavailable or the service is not eligible.
Keep public discovery documents readable according to ODP’s access rules. Requiring TAP on a protected operation does not justify blocking the public Service Document. For payment testing, use Pay with MPP or Pay with x402 against your test seller, and verify payment independently of the TAP result.
- Accept a correctly signed request and confirm that the intended handler can run after all other required checks.
- Change the path, query, method or body of a signed request. Confirm rejection before the protected operation runs.
- Submit an expired signature, a future-dated signature, an unknown key and a malformed signature. Confirm rejection rather than unsigned fallback on a TAP-required route.
- Replay the identical valid signature. Confirm that only the first use succeeds, including when requests reach different workers.
- Test key retrieval failure with both a usable cached key and an empty cache. Confirm that the latter cannot grant trusted-agent access.
- Send a valid TAP signature without required authentication or payment. Confirm that recognition does not bypass those requirements.
Use controlled signed fixtures for negative tests and a real signed request for the running-system check. Keep these checks alongside your project’s unit tests, integration tests and coverage requirements.
Continue your integration
Deliver paid results
Connect payment confirmation to protected work and response delivery.
Test your integration
Check the complete buyer and seller flow against your running service.