TAP HTTP
HTTP DIDComm server implementation for the Transaction Authorization Protocol (TAP), providing secure message exchange via standard HTTP endpoints.
Installation
From crates.io (recommended)
This installs two binaries:
tap-http- The TAP HTTP DIDComm servertap-payment-simulator- A tool for testing TAP payment flows
From source
Verify installation
Prerequisites
- Rust 1.71.0 or later
Quick start
# Start the server (creates an ephemeral agent automatically)
# In another terminal, test with the payment simulator
Features
- DIDComm HTTP Endpoint: Exposes a secure HTTP endpoint for DIDComm messaging
- Integration with tap-node: Seamlessly forwards messages to a tap-node instance
- Ephemeral Agent Support: Creates an ephemeral agent with did:key by default
- Message Validation: Validates incoming DIDComm messages
- Response Handling: Proper handling of responses and errors
- Outgoing Message Delivery: HTTP client for sending outgoing DIDComm messages
- Event Logging System: Comprehensive event tracking with configurable logging destinations
- Security: Support for HTTPS/TLS and rate limiting (configurable)
- Comprehensive Error Handling: Structured error responses with appropriate HTTP status codes
- Payment Flow Simulator: Included CLI tool for simulating TAP payment flows
- Persistent Storage: SQLite database using async SQLx for message audit trail and transaction tracking
- Web DID Hosting: Optional
/.well-known/did.jsonendpoint for hostingdid:webDID documents (enabled via--enable-web-did)
Usage
use ;
use ;
use DefaultAgent;
use Duration;
async
HTTP Endpoints
POST /{didcomm_endpoint}
The main endpoint for receiving DIDComm messages. The endpoint path is configurable (default is /didcomm):
POST /didcomm HTTP/1.1
Host: example.com
Content-Type: application/didcomm-encrypted+json
eyJhbGciOiJFQ0RILUVTK0EyNTZLVyIsImFwdiI6InpRbFpBQ0pZVFpnZUNidFhvd0xkX18zdWNmQmstLW0za2NXekQyQ0kiLCJlbmMiOiJBMjU2R0NNIiwiZXBrIjp7ImNydiI6IlAtMjU2Iiwia3R5IjoiRUMiLCJ4IjoiZ1RxS2ZaQk45bXpLNHZhX1l2TXQ2c0VkNEw0X1Q3aS1PVmtvMGFaVHUwZyIsInkiOiJQOHdyeFFDYmFZckdPdTRXWGM0R05WdWkyLWVpbEhYNUNHZXo5dk9FX2ZrIn0sInByb3RlY3RlZCI6ImV5SmtjeUk2ZXlKQmJXRjZiMjVCZEhSeWFXSmhkR1ZVWVdkZmMxOGdUVVZCTUZVMVRFMVlXRkF5UmtkRWFEVmFkejA5SW4xOSIsInR5cCI6ImFwcGxpY2F0aW9uL2RpZGNvbW0tZW5jcnlwdGVkK2pzb24ifQ...
When unpacked, the above message would contain a TAP protocol message like:
GET /health
Health check endpoint for monitoring system availability:
GET /health HTTP/1.1
Host: example.com
Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "ok",
"version": "0.1.0"
}
GET /.well-known/did.json (opt-in)
When the server is started with --enable-web-did, it serves a did:web DID document at the standard well-known path. This allows the server to act as a did:web identity — other agents can resolve did:web:yourdomain.com by fetching https://yourdomain.com/.well-known/did.json.
The endpoint derives the did:web DID from the HTTP Host header, so a single server can respond correctly when reached via different hostnames.
How it works:
- A request arrives at
GET /.well-known/did.json. - The
Hostheader is validated and mapped to adid:webDID (e.g.example.com→did:web:example.com). - If an agent for that DID already exists in the node, its DID document is returned.
- Otherwise, a new agent with fresh Ed25519 keys is created, registered, and its DID document is returned. The document includes a
DIDCommMessagingservice endpoint pointing to the server's/didcommpath.
# Start the server with web DID hosting enabled
# Resolve the DID document
Example response:
This endpoint is disabled by default. Enable it with the --enable-web-did flag or by setting the TAP_ENABLE_WEB_DID environment variable.
Response Formats and Status Codes
Success Response
For successfully processed messages:
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "success",
"message": "Message received and processed"
}
Error Response
For validation and other errors:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"status": "error",
"error": {
"type": "validation_error",
"message": "Unsupported message type: https://didcomm.org/basicmessage/2.0/message, expected TAP protocol message"
}
}
Message Validation and Processing
The server performs several validation steps on incoming messages:
-
Message Unpacking:
- Decrypts and verifies message signatures using the TAP Agent
- Handles different security modes (Plain, Signed, AuthCrypt)
- Validates cryptographic integrity
-
DID Verification:
- Resolves DIDs using the TAP Agent's resolver
- Validates sender's verification methods
- Checks service endpoints for routing
-
Protocol Validation:
- Validates message types against TAP protocol schemas
- Verifies required fields (id, type, from, to)
- Validates message timestamps and sequence
-
TAP Node Processing:
- Forwards valid messages to the TAP Node for business logic processing
- Returns responses from the node to the sender
- Logs process events and errors
Configuration Options
The server can be configured with the following options in TapHttpConfig:
TLS Configuration
Enable HTTPS with TLS certificates:
let config = TapHttpConfig ;
Event Logging
Configure event logging to track server activity:
use ;
let config = TapHttpConfig ;
The event logging system captures:
- Server startup and shutdown
- HTTP request/response details
- DIDComm message processing
- Error events with detailed information
Custom event subscribers can also be implemented:
use Arc;
use async_trait;
use ;
;
// After creating the server
let custom_handler = new;
server.event_bus.subscribe;
Rate Limiting
Configure rate limiting to prevent abuse:
let config = TapHttpConfig ;
DIDComm Client
The package includes an HTTP client for sending DIDComm messages to other endpoints:
use DIDCommClient;
use ;
use Transfer;
// Create a TAP Agent
let = new_ephemeral?;
// Create client with custom timeout
let client = new;
// Create a message
let transfer = Transfer ;
// Pack a message using the agent
let recipient_did = "did:web:example.com";
let = agent.send_message.await?;
// Send the packed message to a recipient's endpoint
let response = client.deliver_message.await?;
// Process the response
println!;
You can also use the built-in delivery functionality of the TAP Agent:
// The third parameter (true) enables automatic delivery
let = agent.send_message.await?;
// Check delivery results
for result in delivery_results
Security Considerations
- Use TLS in production environments
- Configure rate limiting to prevent abuse
- Ensure proper validation and authentication of messages
- Consider running behind a reverse proxy for additional security layers
Error Handling
The server uses a comprehensive error handling system with appropriate HTTP status codes:
400 Bad Request: Format and validation errors401 Unauthorized: Authentication errors429 Too Many Requests: Rate limiting500 Internal Server Error: Server-side errors503 Service Unavailable: Configuration errors
Command Line Usage
The tap-http package includes binary executables that can be run from the command line:
TAP HTTP Server
Installation
The TAP HTTP server can be installed in several ways:
# From crates.io (recommended for most users)
# From the repository (if you have it cloned)
# Run the HTTP server with default settings (creates ephemeral agent)
# Run with custom options
# Run with stored key (uses default from ~/.tap/keys.json)
# Run with a specific stored key by its DID
# Run with custom logging options
Docker
The easiest way to run tap-http is with Docker. All persistent state (keys, databases, logs) is stored in a single volume at /data/tap.
Quick Start
# Build and run with docker compose
# View logs
# Stop
Build the Image Manually
Run with Docker
# Run with a named volume for persistent storage
# Run with a host directory for easy inspection of data
# Pass additional CLI flags
Persistent Storage
The container stores all state under /data/tap, which maps to:
| Path | Contents |
|---|---|
/data/tap/keys.json |
Agent key store |
/data/tap/logs/ |
Event log files |
/data/tap/<did>/transactions.db |
Per-agent SQLite databases |
Back up this volume to preserve keys and transaction history across container recreations.
Environment Variables
Configure the container with environment variables via docker compose or docker run -e:
See the full list of environment variables in the Environment Variables section below.
Inspecting Data
# Access the SQLite database from the host
# Query the database directly
# Tail event logs
Command Line Options for tap-http
After installation, you can use the tap-http command to run a TAP HTTP server:
USAGE:
tap-http [OPTIONS]
OPTIONS:
-h, --host <HOST> Host to bind to [default: 127.0.0.1]
-p, --port <PORT> Port to listen on [default: 8000]
-e, --endpoint <ENDPOINT> Path for the DIDComm endpoint [default: /didcomm]
-t, --timeout <SECONDS> Request timeout in seconds [default: 30]
--use-stored-key Use a key from the local key store (~/.tap/keys.json)
--agent-did <DID> Specific DID to use from key store (when --use-stored-key is set)
--generate-key Generate a new key and save it to the key store
--key-type <TYPE> Key type for generation [default: ed25519] [possible values: ed25519, p256, secp256k1]
--logs-dir <DIR> Directory for event logs [default: ./logs]
--structured-logs Use structured JSON logging [default: true]
--db-path <PATH> Path to the database file [default: tap-http.db]
--rate-limit <RATE> Rate limit in requests per minute [default: 60]
--tls-cert <PATH> Path to TLS certificate file
--tls-key <PATH> Path to TLS private key file
--enable-web-did Enable /.well-known/did.json endpoint for did:web hosting
-v, --verbose Enable verbose logging
--help Print help information
--version Print version information
Environment Variables for tap-http
You can also configure the server using environment variables:
# Server configuration
# Agent configuration
# Logging configuration
# Storage configuration
# Security configuration
# Web DID hosting
# Run the server (will use environment variables)
Decision Modes
tap-http supports three decision modes that control how transaction authorization, settlement, and policy decisions are handled:
Auto Mode (default)
All decisions are automatically approved. This is the default behavior when no decision flags are set.
# or explicitly:
Poll Mode
Decisions are logged to the decision_log table in each agent's SQLite database. An external process (e.g., a separate tap-mcp instance connected to an AI agent) polls for pending decisions and acts on them using standard MCP tools.
The workflow:
- tap-http receives a Transfer message, FSM hits a decision point
DecisionLogHandlerwrites the decision to thedecision_logtable (status:pending)- An external tap-mcp process calls
tap_list_pending_decisionsto see pending decisions - The external process calls
tap_authorize(ortap_reject,tap_settle, etc.) - The decision is automatically resolved in the
decision_logwhen the action succeeds
Decisions are also automatically expired when a transaction reaches a terminal state (rejected, cancelled, reverted).
Exec Mode
A long-running child process is spawned and communicates via JSON-RPC 2.0 over stdin/stdout. This is activated by providing --decision-exec:
The child process receives decision requests via stdin and can call MCP tools via stdout. See the External Decision PRD for the full protocol specification.
Decision CLI Flags
| Flag | Env Var | Default | Description |
|---|---|---|---|
-M, --decision-mode |
TAP_DECISION_MODE |
auto |
Decision handling: auto, poll, or exec (implied by -D) |
-D, --decision-exec |
TAP_DECISION_EXEC |
— | Path to external decision executable (implies exec mode) |
-A, --decision-exec-args |
TAP_DECISION_EXEC_ARGS |
— | Comma-separated arguments for the executable |
-S, --decision-subscribe |
TAP_DECISION_SUBSCRIBE |
decisions |
Event forwarding: decisions or all |
Decision Auto-Resolution
When action tools (tap_authorize, tap_reject, tap_settle, tap_cancel, tap_revert) are called — whether from the spawned child process or a separate tap-mcp instance — matching pending decisions are automatically resolved in the database:
| Action Tool | Resolves Decision Type | Resolution |
|---|---|---|
tap_authorize |
authorization_required |
authorize |
tap_reject |
all pending for transaction | reject |
tap_settle |
settlement_required |
settle |
tap_cancel |
all pending for transaction | cancel |
tap_revert |
all pending for transaction | revert |
TAP Payment Flow Simulator
The package also includes a payment flow simulator that can be used to test the TAP HTTP server:
# Run the payment simulator
# Run with custom amount and currency
Command Line Options for tap-payment-simulator
The payment simulator is installed together with the tap-http package. You can use it to test your TAP HTTP server:
USAGE:
tap-payment-simulator --url <server-url> --did <server-agent-did> [OPTIONS]
REQUIRED ARGUMENTS:
--url <URL> URL of the TAP HTTP server's DIDComm endpoint
--did <DID> DID of the server's agent
OPTIONS:
--amount <AMOUNT> Amount to transfer [default: 100.00]
--currency <CURRENCY> Currency code [default: USD]
-v, --verbose Enable verbose logging
--help Print help information
--version Print version information
Examples
Check the examples directory for complete usage examples:
http_message_flow.rs: Basic HTTP message flowwebsocket_message_flow.rs: WebSocket message flow exampleevent_logger_demo.rs: Demonstration of event logging configuration
To run the examples:
# Run the HTTP message flow example
# Run the WebSocket message flow example (with websocket feature)
# Run the event logger demo
Creating a TAP Payment Flow
Using the tap-payment-simulator tool, you can easily test a complete TAP payment flow:
-
Install the HTTP server and payment simulator (if not already installed):
This installs both
tap-httpandtap-payment-simulatorbinaries. -
Start the tap-http server with an ephemeral agent:
The server will display the generated DID on startup:
TAP HTTP Server started with agent DID: did:key:z6Mk... -
In another terminal, run the payment simulator to send messages to the server:
The payment simulator will also display its agent DID:
Payment simulator using agent DID: did:key:z6Mk... -
The simulator will:
- Create its own ephemeral agent
- Send a payment request message to the server
- Wait for 2 seconds
- Send a transfer message to the server
- Both messages will use the same transaction ID to create a complete payment flow
-
Check the server logs to see the received messages and how they were processed:
tail -f ./logs/tap-http.log
This simulates a complete payment flow between two agents, demonstrating how the TAP protocol works in practice.
Integration with tap-agent Features
The TAP HTTP server leverages all the key features of the TAP Agent:
Key Management
The server can use any of the TAP Agent's key management approaches:
- Ephemeral keys for testing and development (default)
- Stored keys from the local key store (
~/.tap/keys.json) - shared withtap-agent-cli - Generated keys created at startup and optionally saved
To generate and manage keys for use with tap-http, you can use the tap-agent-cli tool:
# Install the tap-agent CLI
# Generate and save a key for later use with tap-http
# View your stored keys
# Then use a stored key with tap-http
# Use a specific stored key
DID Resolution
The server uses the TAP Agent's DID resolution capabilities:
- Support for
did:keyanddid:webby default - Custom DID method resolvers can be added
- Automatic endpoint discovery for message routing
Secure Messaging
All security modes from the TAP Agent are supported:
- Plain - No security (for testing)
- Signed - Digital signatures for integrity
- AuthCrypt - Encrypted messages for confidentiality
Service Endpoint Handling
The server acts as a service endpoint for incoming messages:
- Configure the URL in your DID document's service section
- Other agents can discover this endpoint via DID resolution
- Messages will be automatically routed to your endpoint
Persistent Storage
The TAP HTTP server includes built-in SQLite storage using async SQLx for:
- Message Audit Trail: All incoming and outgoing messages are logged
- Transaction Tracking: Transfer and Payment messages are tracked separately
- Automatic Schema Management: Database migrations run automatically on startup
- JSON Column Support: Message content is stored as validated JSON
Storage Configuration
By default, the server creates a database file at tap-http.db in the current directory. You can customize this location:
# Via command line
# Via environment variable
Database Schema
The storage system maintains two tables:
-
messages - Complete audit trail of all messages:
- message_id (unique identifier)
- message_type (TAP message type)
- from_did, to_did (sender and recipient DIDs)
- direction (incoming/outgoing)
- message_json (full message content as JSON column type)
- created_at (timestamp)
-
transactions - Business logic for Transfer and Payment messages:
- type (transfer/payment)
- reference_id (message ID)
- status (pending/completed/failed/cancelled)
- from_did, to_did
- thread_id
- created_at, updated_at
Querying the Database
You can query the database directly using SQLite tools:
# View recent messages
# Count messages by type
# View pending transactions
Performance and Scaling
The TAP HTTP server is designed for performance:
- Async Processing - Uses Tokio runtime for efficient concurrency
- Connection Pooling - Reuses connections for outgoing requests
- Minimal Copies - Efficient handling of message payloads
- Horizontal Scaling - Can be deployed across multiple instances
- Efficient Storage - SQLite with async SQLx connection pooling and WAL mode
For high-volume deployments, consider:
- Running behind a load balancer
- Using a Redis-backed rate limiter
- Implementing a message queue for async processing
- Setting up proper monitoring and alerts
- Regular database maintenance and archival