tap-http 0.6.0

HTTP server for the Transaction Authorization Protocol (TAP)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
# 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)

```bash
cargo install tap-http
```

This installs two binaries:
- `tap-http` - The TAP HTTP DIDComm server
- `tap-payment-simulator` - A tool for testing TAP payment flows

### From source

```bash
git clone https://github.com/TransactionAuthorizationProtocol/tap-rs.git
cd tap-rs
cargo install --path tap-http
```

### Verify installation

```bash
tap-http --help
tap-payment-simulator --help
```

### Prerequisites

- [Rust]https://www.rust-lang.org/tools/install 1.71.0 or later

### Quick start

```bash
# Start the server (creates an ephemeral agent automatically)
tap-http

# In another terminal, test with the payment simulator
tap-payment-simulator --url http://localhost:8000/didcomm --did <DID printed by server>
```

## 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.json` endpoint for hosting `did:web` DID documents (enabled via `--enable-web-did`)

## Usage

```rust
use tap_http::{TapHttpConfig, TapHttpServer};
use tap_node::{NodeConfig, TapNode};
use tap_agent::DefaultAgent;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create a TAP Agent - either load from stored keys or create ephemeral
    let agent = DefaultAgent::from_stored_or_ephemeral(None, true);
    println!("Server using agent with DID: {}", agent.get_agent_did());
    
    // Create a TAP Node configuration with storage
    let mut node_config = NodeConfig::default();
    node_config.storage_path = Some("tap-http.db".into());
    
    // Create a TAP Node for message processing
    let mut node = TapNode::new(node_config);
    node.init_storage().await?;
    node.register_agent(Arc::new(agent)).await?;
    
    // Configure the HTTP server with custom settings
    let config = TapHttpConfig {
        host: "0.0.0.0".to_string(),                  // Listen on all interfaces
        port: 8080,                                   // Custom port
        didcomm_endpoint: "/api/didcomm".to_string(), // Custom endpoint path
        request_timeout_secs: 60,                     // 60-second timeout for requests
        ..TapHttpConfig::default()
    };
    
    // Create and start the server
    let mut server = TapHttpServer::new(config, node);
    server.start().await?;
    
    // Wait for shutdown signal
    tokio::signal::ctrl_c().await?;
    
    // Gracefully stop the server
    server.stop().await?;
    
    Ok(())
}
```

## HTTP Endpoints

### POST /{didcomm_endpoint}

The main endpoint for receiving DIDComm messages. The endpoint path is configurable (default is `/didcomm`):

```http
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:

```json
{
  "id": "1234567890",
  "type": "https://tap.rsvp/schema/1.0#transfer",
  "body": {
    "amount": "100.00",
    "asset": "eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f",
    "transaction_id": "tx-123456"
  },
  "from": "did:example:sender",
  "to": ["did:example:recipient"],
  "created_time": 1620000000
}
```

### GET /health

Health check endpoint for monitoring system availability:

```http
GET /health HTTP/1.1
Host: example.com
```

Response:

```http
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](https://w3c-ccg.github.io/did-method-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:**

1. A request arrives at `GET /.well-known/did.json`.
2. The `Host` header is validated and mapped to a `did:web` DID (e.g. `example.com``did:web:example.com`).
3. If an agent for that DID already exists in the node, its DID document is returned.
4. Otherwise, a new agent with fresh Ed25519 keys is created, registered, and its DID document is returned. The document includes a `DIDCommMessaging` service endpoint pointing to the server's `/didcomm` path.

```bash
# Start the server with web DID hosting enabled
tap-http --enable-web-did

# Resolve the DID document
curl https://yourdomain.com/.well-known/did.json
```

Example response:

```json
{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://w3id.org/security/suites/ed25519-2018/v1"
  ],
  "id": "did:web:yourdomain.com",
  "verificationMethod": [
    {
      "id": "did:web:yourdomain.com#key-0",
      "type": "Ed25519VerificationKey2018",
      "controller": "did:web:yourdomain.com",
      "publicKeyMultibase": "z6Mk..."
    }
  ],
  "authentication": ["did:web:yourdomain.com#key-0"],
  "keyAgreement": ["did:web:yourdomain.com#key-1"],
  "service": [
    {
      "id": "did:web:yourdomain.com#didcomm",
      "type": "DIDCommMessaging",
      "serviceEndpoint": "https://yourdomain.com/didcomm"
    }
  ]
}
```

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
HTTP/1.1 200 OK
Content-Type: application/json

{
  "status": "success",
  "message": "Message received and processed"
}
```

### Error Response

For validation and other errors:

```http
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:

1. **Message Unpacking**:
   - Decrypts and verifies message signatures using the TAP Agent
   - Handles different security modes (Plain, Signed, AuthCrypt)
   - Validates cryptographic integrity

2. **DID Verification**:
   - Resolves DIDs using the TAP Agent's resolver
   - Validates sender's verification methods
   - Checks service endpoints for routing

3. **Protocol Validation**:
   - Validates message types against TAP protocol schemas
   - Verifies required fields (id, type, from, to)
   - Validates message timestamps and sequence

4. **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`:

```rust
pub struct TapHttpConfig {
    /// The host address to bind to.
    pub host: String,

    /// The port to bind to.
    pub port: u16,

    /// The endpoint path for receiving DIDComm messages.
    pub didcomm_endpoint: String,

    /// Optional rate limiting configuration.
    pub rate_limit: Option<RateLimitConfig>,

    /// Optional TLS configuration.
    pub tls: Option<TlsConfig>,

    /// Default timeout for outbound HTTP requests in seconds.
    pub request_timeout_secs: u64,
    
    /// Event logger configuration (for tracking server events).
    pub event_logger: Option<EventLoggerConfig>,
    
    /// CORS configuration for cross-origin requests.
    pub cors: Option<CorsConfig>,

    /// Enable /.well-known/did.json endpoint for did:web hosting.
    pub enable_web_did: bool,
}
```

### TLS Configuration

Enable HTTPS with TLS certificates:

```rust
let config = TapHttpConfig {
    // ...other settings
    tls: Some(TlsConfig {
        cert_path: "/path/to/cert.pem".to_string(),
        key_path: "/path/to/key.pem".to_string(),
    }),
    // ...
};
```

### Event Logging

Configure event logging to track server activity:

```rust
use tap_http::event::{EventLoggerConfig, LogDestination};

let config = TapHttpConfig {
    // ...other settings
    event_logger: Some(EventLoggerConfig {
        destination: LogDestination::File {
            path: "./logs/tap-http.log".to_string(), // Default location
            max_size: Some(10 * 1024 * 1024),        // 10 MB
            rotate: true,                            // Enable rotation
        },
        structured: true,      // Use JSON format
        log_level: log::Level::Info,
        include_payloads: false, // Don't log sensitive message payloads
    }),
    // ...
};
```

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:

```rust
use std::sync::Arc;
use async_trait::async_trait;
use tap_http::event::{EventSubscriber, HttpEvent};

struct CustomEventHandler;

#[async_trait]
impl EventSubscriber for CustomEventHandler {
    async fn handle_event(&self, event: HttpEvent) {
        // Custom handling of events
        println!("Event: {:?}", event);
    }
}

// After creating the server
let custom_handler = Arc::new(CustomEventHandler);
server.event_bus().subscribe(custom_handler);
```

### Rate Limiting

Configure rate limiting to prevent abuse:

```rust
let config = TapHttpConfig {
    // ...other settings
    rate_limit: Some(RateLimitConfig {
        max_requests: 100,  // Maximum requests per window
        window_secs: 60,    // Time window in seconds
    }),
    // ...
};
```

## DIDComm Client

The package includes an HTTP client for sending DIDComm messages to other endpoints:

```rust
use tap_http::DIDCommClient;
use tap_agent::{Agent, DefaultAgent};
use tap_msg::message::Transfer;

// Create a TAP Agent
let (agent, agent_did) = DefaultAgent::new_ephemeral()?;

// Create client with custom timeout
let client = DIDCommClient::new(std::time::Duration::from_secs(30));

// Create a message
let transfer = Transfer {
    // Message fields...
    transaction_id: uuid::Uuid::new_v4().to_string(),
};

// Pack a message using the agent
let recipient_did = "did:web:example.com";
let (packed_message, _) = agent.send_message(&transfer, vec![recipient_did], false).await?;

// Send the packed message to a recipient's endpoint
let response = client.deliver_message(
    "https://recipient.example.com/didcomm",
    &packed_message
).await?;

// Process the response
println!("Delivery status: {}", response.status());
```

You can also use the built-in delivery functionality of the TAP Agent:

```rust
// The third parameter (true) enables automatic delivery
let (_, delivery_results) = agent.send_message(&transfer, vec![recipient_did], true).await?;

// Check delivery results
for result in delivery_results {
    if let Some(status) = result.status {
        println!("Delivery status: {}", status);
    }
}
```

## 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 errors
- `401 Unauthorized`: Authentication errors
- `429 Too Many Requests`: Rate limiting
- `500 Internal Server Error`: Server-side errors
- `503 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:

```bash
# From crates.io (recommended for most users)
cargo install tap-http

# From the repository (if you have it cloned)
cargo install --path tap-rs/tap-http

# Run the HTTP server with default settings (creates ephemeral agent)
tap-http

# Run with custom options
tap-http --host 0.0.0.0 --port 8080 --endpoint /api/didcomm

# Run with stored key (uses default from ~/.tap/keys.json)
tap-http --use-stored-key

# Run with a specific stored key by its DID
tap-http --use-stored-key --agent-did did:key:z6Mk...

# Run with custom logging options
tap-http --logs-dir /var/log/tap --structured-logs
```

## 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

```bash
# Build and run with docker compose
docker compose up -d

# View logs
docker compose logs -f tap-http

# Stop
docker compose down
```

### Build the Image Manually

```bash
docker build -t tap-http .
```

### Run with Docker

```bash
# Run with a named volume for persistent storage
docker run -d \
  --name tap-http \
  -p 8000:8000 \
  -v tap-data:/data/tap \
  tap-http

# Run with a host directory for easy inspection of data
docker run -d \
  --name tap-http \
  -p 8000:8000 \
  -v ./tap-data:/data/tap \
  tap-http

# Pass additional CLI flags
docker run -d \
  --name tap-http \
  -p 8000:8000 \
  -v tap-data:/data/tap \
  tap-http --verbose --structured-logs
```

### 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`:

```bash
docker run -d \
  --name tap-http \
  -p 9000:9000 \
  -v tap-data:/data/tap \
  -e TAP_HTTP_PORT=9000 \
  -e TAP_STRUCTURED_LOGS=true \
  -e TAP_AGENT_DID=did:key:z6Mk... \
  -e TAP_AGENT_KEY=<base64-private-key> \
  tap-http
```

See the full list of environment variables in the [Environment Variables](#environment-variables-for-tap-http) section below.

### Inspecting Data

```bash
# Access the SQLite database from the host
docker run --rm -v tap-data:/data alpine ls -la /data/tap/

# Query the database directly
docker exec tap-http sqlite3 /data/tap/*/transactions.db \
  "SELECT message_id, message_type, direction FROM messages LIMIT 10;"

# Tail event logs
docker exec tap-http tail -f /data/tap/logs/tap-http.log
```

## 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:

```bash
# Server configuration
export TAP_HTTP_HOST=0.0.0.0
export TAP_HTTP_PORT=8080
export TAP_HTTP_DIDCOMM_ENDPOINT=/api/didcomm
export TAP_HTTP_TIMEOUT=60

# Agent configuration
export TAP_USE_STORED_KEY=true
export TAP_AGENT_DID=did:key:z6Mk...
export TAP_GENERATE_KEY=false
export TAP_KEY_TYPE=ed25519

# Logging configuration
export TAP_LOGS_DIR=/var/log/tap
export TAP_STRUCTURED_LOGS=true
export TAP_LOG_LEVEL=info

# Storage configuration
export TAP_NODE_DB_PATH=/var/lib/tap/tap-http.db

# Security configuration
export TAP_RATE_LIMIT=100
export TAP_TLS_CERT=/path/to/cert.pem
export TAP_TLS_KEY=/path/to/key.pem

# Web DID hosting
export TAP_ENABLE_WEB_DID=true

# Run the server (will use environment variables)
tap-http
```

## 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.

```bash
tap-http
# or explicitly:
tap-http --decision-mode auto
```

### 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.

```bash
tap-http --decision-mode poll
```

The workflow:
1. tap-http receives a Transfer message, FSM hits a decision point
2. `DecisionLogHandler` writes the decision to the `decision_log` table (status: `pending`)
3. An external tap-mcp process calls `tap_list_pending_decisions` to see pending decisions
4. The external process calls `tap_authorize` (or `tap_reject`, `tap_settle`, etc.)
5. The decision is **automatically resolved** in the `decision_log` when 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`:

```bash
tap-http --decision-exec /path/to/decision-handler
tap-http --decision-exec /path/to/handler --decision-exec-args "arg1,arg2"
tap-http --decision-exec /path/to/handler --decision-subscribe all
```

The child process receives decision requests via stdin and can call MCP tools via stdout. See the [External Decision PRD](../prds/external-decision.md) 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:

```bash
# Run the payment simulator
tap-payment-simulator --url http://localhost:8000/didcomm --did did:key:z6Mk...

# Run with custom amount and currency
tap-payment-simulator --url http://localhost:8000/didcomm --did did:key:z6Mk... --amount 500 --currency EUR
```

## 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 flow
- `websocket_message_flow.rs`: WebSocket message flow example
- `event_logger_demo.rs`: Demonstration of event logging configuration

To run the examples:

```bash
# Run the HTTP message flow example
cargo run --example http_message_flow

# Run the WebSocket message flow example (with websocket feature)
cargo run --example websocket_message_flow --features websocket

# Run the event logger demo
cargo run --example event_logger_demo
```

## Creating a TAP Payment Flow

Using the tap-payment-simulator tool, you can easily test a complete TAP payment flow:

1. Install the HTTP server and payment simulator (if not already installed):
   ```bash
   cargo install tap-http
   ```
   This installs both `tap-http` and `tap-payment-simulator` binaries.

2. Start the tap-http server with an ephemeral agent:
   ```bash
   tap-http --verbose
   ```
   The server will display the generated DID on startup:
   ```
   TAP HTTP Server started with agent DID: did:key:z6Mk...
   ```

2. In another terminal, run the payment simulator to send messages to the server:
   ```bash
   tap-payment-simulator --url http://localhost:8000/didcomm --did did:key:z6Mk...
   ```
   The payment simulator will also display its agent DID:
   ```
   Payment simulator using agent DID: did:key:z6Mk...
   ```

3. 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

4. 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 with `tap-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:

```bash
# Install the tap-agent CLI
cargo install tap-agent

# Generate and save a key for later use with tap-http
tap-agent-cli generate --save

# View your stored keys
tap-agent-cli keys list

# Then use a stored key with tap-http
tap-http --use-stored-key

# Use a specific stored key
tap-http --use-stored-key --agent-did did:key:z6Mk...
```

### DID Resolution

The server uses the TAP Agent's DID resolution capabilities:

- Support for `did:key` and `did:web` by 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:

1. Configure the URL in your DID document's service section
2. Other agents can discover this endpoint via DID resolution
3. 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:

```bash
# Via command line
tap-http --db-path /var/lib/tap/tap-http.db

# Via environment variable
export TAP_NODE_DB_PATH=/var/lib/tap/tap-http.db
tap-http
```

### Database Schema

The storage system maintains two tables:

1. **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)

2. **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:

```bash
# View recent messages
sqlite3 tap-http.db "SELECT message_id, message_type, direction, created_at FROM messages ORDER BY created_at DESC LIMIT 10;"

# Count messages by type
sqlite3 tap-http.db "SELECT message_type, COUNT(*) FROM messages GROUP BY message_type;"

# View pending transactions
sqlite3 tap-http.db "SELECT * FROM transactions WHERE status = 'pending';"
```

## 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