From c488b6b8b25c12a991631a830d1208d92b535125 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:05:18 +0100 Subject: [PATCH 01/32] Add TAIP-20: Trusted Connections using Connect and Authorize This TAIP introduces a Connect message type for establishing trusted connections between Entities. Key features: - New Connect message with establish/update actions - Reuses Authorize (approve), Reject (decline), Cancel (terminate) - Supports DDQ exchange, mutual trust, and whitelisting - Fully backward compatible with existing TAP implementations --- TAIPs/taip-20.md | 585 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 585 insertions(+) create mode 100644 TAIPs/taip-20.md diff --git a/TAIPs/taip-20.md b/TAIPs/taip-20.md new file mode 100644 index 0000000..36db164 --- /dev/null +++ b/TAIPs/taip-20.md @@ -0,0 +1,585 @@ +--- +taip: 20 +title: Connections +status: Draft +type: Standard +author: Pelle Braendgaard , Martin de Jonge +created: 2026-01-26 +requires: 2, 4, 5 +--- + +## Simple Summary +A standardized way for Entities to establish trusted connections, exchange DDQ documents, and signal mutual trust relationships. This TAIP introduces one new `Connect` message and reuses three existing TAIP-4 messages (`Authorize` for approval, `Reject` for decline, `Cancel` for termination). + +## Abstract +This TAIP extends the existing TAP protocol with a `Connect` message type for establishing trusted connections between VASPs, and leverages the existing `Authorize`, `Reject`, `Cancel` messages from TAIP-4 to manage DDQ access, mutual trust relationships, and whitelisting capabilities. This approach minimizes new message types and builds on established TAP patterns. +Within the connections the protocol establishes different connection types, which differ in trust level: +**ddq-access**: View DDQ documents +**mutual-trust**: Established trust relationship, but transactions still reviewed individually +**whitelist**: Pre-approved automatic transaction processing (typically requires mutual-trust first) +Typical progression: **ddq-access → mutual-trust → whitelist** + +## Motivation + +This adds to TAP a standardized way for establishing pre-approved trusted connections. This TAIP: +- Introduces one new message type (`Connect`) for relationship establishment +- Reuses existing message types from TAIP-4 for all approval/denial flows +- Extends the semantic meaning of `Authorize`, `Reject`, `Cancel` to cover non-payment authorization scenarios +- Provides a foundation for DDQ exchange, mutual trust, and whitelisting + +## Specification + +### New Message Type: Connect + +#### Connect Message Body + +The `Connect` message body contains: + +- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` +- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Connect` +- `action` - REQUIRED string indicating the connection action: `establish` or `update` (use Cancel from TAIP-4 to terminate connections) +- `connectionTypes` - REQUIRED (for establish/update) array of strings specifying requested connection types: `ddq-access`, `mutual-trust`, `whitelist` +- `purpose` - OPTIONAL string providing human-readable reason for connection +- `expiry` - OPTIONAL ISO 8601 timestamp when connection should automatically terminate (distinct from message `expires_time`) +- `metadata` - OPTIONAL object containing additional context + +**Complete DIDComm message example:** + +```json +{ + "id": "conn-123e4567-e89b-12d3-a456-426614174000", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasps.id:initiator", + "to": ["did:web:vasps.id:recipient"], + "created_time": 1769086601, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "action": "establish", + "connectionTypes": ["ddq-access", "mutual-trust"], + "purpose": "Request DDQ access for compliance verification", + "expiry": "2026-01-26T00:00:00Z" + } +} +``` + +### Extending TAIP-4 Messages for Connections + +The existing messages from TAIP-4 are reused for connection management: + +#### Authorize - Connection Approval + +When responding to `Connect` messages with approval, use the standard `Authorize` message from TAIP-4: + +**Authorize Body Structure (from TAIP-4):** +- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` +- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Authorize` +- `settlementAddress` - OPTIONAL (omitted for connection responses) +- `settlementAsset` - OPTIONAL (omitted for connection responses) +- `amount` - OPTIONAL (omitted for connection responses) +- `expiry` - OPTIONAL ISO 8601 timestamp when the connection authorization expires + +**Connection-Specific Attributes (new, added to body):** +- `approvedTypes` - OPTIONAL array of approved connection types (subset of requested types) +- `ddqDocument` - OPTIONAL object containing DDQ document reference (see below) +- `trustLevel` - OPTIONAL string: `whitelisted`, `trusted`, `standard`, `reviewing`, or `suspended` + +**DDQ Document Object Structure:** +- `documentId` - REQUIRED string unique identifier for the document +- `version` - OPTIONAL string document version +- `accessUrl` - OPTIONAL string HTTPS URL for document retrieval +- `checksum` - OPTIONAL string SHA-256 hash for integrity verification +- `expiresAt` - OPTIONAL ISO 8601 timestamp when document access expires + +**Complete approval example:** + +```json +{ + "id": "auth-456", + "type": "https://tap.rsvp/schema/1.0#Authorize", + "from": "did:web:vasps.id:recipient", + "to": ["did:web:vasps.id:initiator"], + "thid": "conn-123e4567-e89b-12d3-a456-426614174000", + "created_time": 1769087421, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Authorize", + "approvedTypes": ["ddq-access", "mutual-trust"], + "expiry": "2026-01-26T00:00:00Z", + "ddqDocument": { + "documentId": "ddq-uuid-789", + "version": "2024-Q4", + "accessUrl": "https://vasps.id/api/ddq/ddq-uuid-789", + "checksum": "sha256:abc123...", + "expiresAt": "2026-12-31T23:59:59Z" + }, + "trustLevel": "trusted" + } +} +``` + +#### Reject - Connection Declined + +When declining a `Connect` request, use the standard `Reject` message from TAIP-4: + +**Reject Body Structure (from TAIP-4):** +- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` +- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Reject` +- `reason` - OPTIONAL string explaining the rejection + +**Complete rejection example:** + +```json +{ + "id": "reject-789", + "type": "https://tap.rsvp/schema/1.0#Reject", + "from": "did:web:vasps.id:recipient", + "to": ["did:web:vasps.id:initiator"], + "thid": "conn-123e4567-e89b-12d3-a456-426614174000", + "created_time": 1769087421, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Reject", + "reason": "Insufficient compliance documentation" + } +} +``` + +#### Cancel - Connection Termination + +To terminate an existing connection, use the standard `Cancel` message from TAIP-4: + +**Cancel Body Structure (from TAIP-4):** +- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` +- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Cancel` +- `by` - REQUIRED in TAIP-4 for transactions to specify which party (e.g., "originator" or "beneficiary") is canceling. For connections, this can be set to the sender's DID or a simple identifier like "initiator" or "recipient" since the `from` field already identifies the canceling party. +- `reason` - OPTIONAL string explaining the cancellation + +**Complete cancellation example:** + +```json +{ + "id": "cancel-101", + "type": "https://tap.rsvp/schema/1.0#Cancel", + "from": "did:web:vasps.id:initiator", + "to": ["did:web:vasps.id:recipient"], + "thid": "conn-123e4567-e89b-12d3-a456-426614174000", + "created_time": 1769087900, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Cancel", + "by": "did:web:vasps.id:initiator", + "reason": "Business relationship ended" + } +} +``` + +**Note on `by` field for connections:** While TAIP-4 requires the `by` field to specify which party is canceling a transaction (e.g., "originator" or "beneficiary"), connections don't have these predefined roles. For connection cancellations, implementations MAY set `by` to the sender's DID (matching the `from` field) or use simple identifiers like "initiator" or "recipient". The `from` field in the message envelope is sufficient to identify who is terminating the connection. + +### Connection Types + +The protocol defines three primary connection types: + +1. **`ddq-access`**: Grants access to view DDQ documents + - Allows one party to retrieve the other's Due Diligence Questionnaire + - Can be one-way (requester views owner's DDQ) or mutual + - Example: "We can see each other's compliance documentation" + +2. **`mutual-trust`**: Establishes bilateral trust relationship for compliance purposes + - Both parties acknowledge each other as verified entities + - Reduces verification requirements but transactions still reviewed + - Enables information sharing beyond DDQ + - Example: "We've completed due diligence on each other" + +3. **`whitelist`**: Enables pre-approved, straight-through transaction processing + - Transactions from whitelisted parties proceed with minimal friction + - Automatic approval for transactions (within agreed parameters) + - Typically requires `mutual-trust` to be established first + - Example: "Transactions from this counterparty are auto-approved" + +**Typical progression:** `ddq-access` → `mutual-trust` → `whitelist` + +## Workflows + +### Establishing DDQ Access Connection + +``` +Requester Owner + | | + |--Connect------------------------->| + | (action: establish, | + | connectionTypes: [ddq-access]) | + | | + |<--Authorize----------------------| + | (approvedTypes: [ddq-access], | + | ddqDocument: {...}) | + | | +``` + +### Declining Connection Request + +``` +Requester Owner + | | + |--Connect------------------------->| + | (action: establish) | + | | + |<--Reject-------------------------| + | (reason: "...") | + | | +``` + +### Mutual Whitelisting + +``` +Party A Party B + | | + |--Connect------------------------->| + | (action: establish, | + | connectionTypes: | + | [mutual-trust, whitelist]) | + | | + |<--Authorize----------------------| + | (approvedTypes: | + | [mutual-trust, whitelist], | + | trustLevel: whitelisted) | + | | + |<-Connect-------------------------| + | (action: establish, | + | connectionTypes: | + | [mutual-trust, whitelist]) | + | | + |--Authorize----------------------->| + | (approvedTypes: | + | [mutual-trust, whitelist], | + | trustLevel: whitelisted) | + | | +``` + +### Updating Connection + +``` +Party A Party B + | | + |--Connect------------------------->| + | (action: update, | + | connectionTypes: [whitelist]) | + | [adding whitelist to existing | + | mutual-trust connection] | + | | + |<--Authorize----------------------| + | (approvedTypes: | + | [mutual-trust, whitelist]) | + | | +``` + +### Terminating Connection + +Either party can terminate a connection by sending `Cancel` (from TAIP-4): + +``` +Either Party Other Party + | | + |--Cancel-------------------------->| + | (by: sender's DID or role, | + | reason: "...") | + | | +``` + +Note: When terminating via `Cancel`, the `thid` should reference the original `Connect` message that established the connection. The `by` field can be set to the sender's DID or a simple identifier since connections don't have predefined party roles like transactions do. + +### Requesting Updated DDQ Document + +After a connection is established, a party can request document updates by sending a new `Connect` with `action: update`: + +``` +Requester Owner + | | + |--Connect------------------------->| + | (action: update, | + | connectionTypes: [ddq-access], | + | purpose: "request updated DDQ")| + | | + |<--Authorize----------------------| + | (approvedTypes: [ddq-access], | + | ddqDocument: { | + | documentId: "new-uuid", | + | version: "2025-Q1"}) | + | | +``` + +## Impact Analysis + +### TAIP-4 Changes + +**✅ NO BREAKING CHANGES** + +All existing TAIP-4 message structures remain valid and unchanged. + +**What's Being Extended:** + +1. **Semantic Extension**: `Authorize` can now respond to `Connect` messages (in addition to `Transfer`, `Payment`, etc.) +2. **Optional New Fields**: New optional fields added to `Authorize` body for connection scenarios +3. **Backward Compatible**: Existing TAIP-4 implementations ignore unknown fields + +**Existing TAIP-4 Fields (All Unchanged):** +- ✅ `@context` (REQUIRED) - Still `https://tap.rsvp/schema/1.0` +- ✅ `@type` (REQUIRED) - Still `https://tap.rsvp/schema/1.0#Authorize` +- ✅ `settlementAddress` (OPTIONAL) - Unchanged, omitted for connections +- ✅ `settlementAsset` (OPTIONAL) - Unchanged, omitted for connections +- ✅ `amount` (OPTIONAL) - Unchanged, omitted for connections +- ✅ `expiry` (OPTIONAL) - Unchanged, reused for connection expiry + +**New Optional Fields (Added to Authorize body):** +- ➕ `approvedTypes` (OPTIONAL) - Array of approved connection types +- ➕ `ddqDocument` (OPTIONAL) - Object with DDQ document details +- ➕ `trustLevel` (OPTIONAL) - Trust status indicator + +**Note**: Removed `connectionStatus` and `reason` fields - use existing TAIP-4 message types instead: +- Use `Reject` message (not Authorize) to decline connections +- Use `Cancel` message to terminate connections + +### New Additions + +**New Message Type:** +- `Connect`: New top-level message type + +**Connect Message Mandatory Fields:** +- ✅ `@context` (REQUIRED) +- ✅ `@type` (REQUIRED) +- ✅ `action` (REQUIRED) - Must be `establish` or `update` +- ✅ `connectionTypes` (REQUIRED - Must be `ddq-access`, `mutual-trust`, `whitelist` + + +## State Management + +Implementations SHOULD maintain a local `trusted_connections` table: + +```typescript +interface TrustedConnection { + connectionId: string; + counterpartyDid: string; + connectionTypes: string[]; + status: 'PENDING' | 'APPROVED' | 'DECLINED' | 'REVOKED'; + createdAt: Date; + updatedAt: Date; + expiresAt?: Date; + + // Link to most recent Connect message + connectMessageId: string; + + // Link to most recent Authorize response + authorizeMessageId?: string; + + // DDQ document details (if ddq-access granted) + ddqDocumentId?: string; + ddqAccessUrl?: string; + ddqExpiresAt?: Date; + + // Trust level + trustLevel?: string; + + metadata?: Record; +} +``` + +### Processing Connect Messages + +When receiving a `Connect` message: + +1. Validate the message structure and `action` field +2. For `action: establish`: + - Create new `trusted_connections` entry with status PENDING + - Evaluate connection request based on internal policies +3. For `action: update`: + - Locate existing connection + - Evaluate requested changes +4. Respond with appropriate message: + - **Approve**: Send `Authorize` with `approvedTypes`, optional `ddqDocument`, and `trustLevel` + - **Decline**: Send `Reject` with optional `reason` + +### Processing Authorize/Reject/Cancel Responses + +When receiving a response to your `Connect`: + +**For Authorize responses:** +1. Locate corresponding `trusted_connections` entry via `thid` +2. Update status to APPROVED +3. Store `approvedTypes` array +4. If `ddqDocument` present, store document access details +5. If `trustLevel` present, store trust status +6. Update `expiresAt` from `expiry` field if provided + +**For Reject responses:** +1. Locate corresponding `trusted_connections` entry via `thid` +2. Update status to DECLINED +3. Store optional `reason` +4. Mark connection as not available + +**For Cancel messages:** +1. Locate corresponding `trusted_connections` entry via `thid` +2. Update status to REVOKED +3. Remove access permissions +4. Archive connection record + + +## Test Cases + +### Valid Connect - Establish + +```json +{ + "id": "test-connect-001", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1769086601, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "action": "establish", + "connectionTypes": ["ddq-access"] + } +} +``` + +### Valid Authorize - Connection Approved + +```json +{ + "id": "test-auth-001", + "type": "https://tap.rsvp/schema/1.0#Authorize", + "from": "did:web:vasp-b.example", + "to": ["did:web:vasp-a.example"], + "thid": "test-connect-001", + "created_time": 1769087421, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Authorize", + "approvedTypes": ["ddq-access"], + "ddqDocument": { + "documentId": "ddq-12345", + "accessUrl": "https://vasp-b.example/api/ddq/ddq-12345" + } + } +} +``` + +### Valid Reject - Connection Declined + +```json +{ + "id": "test-reject-001", + "type": "https://tap.rsvp/schema/1.0#Reject", + "from": "did:web:vasp-b.example", + "to": ["did:web:vasp-a.example"], + "thid": "test-connect-001", + "created_time": 1769087421, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Reject", + "reason": "Insufficient compliance documentation" + } +} +``` + +### Valid Cancel - Connection Terminated + +```json +{ + "id": "test-cancel-001", + "type": "https://tap.rsvp/schema/1.0#Cancel", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "thid": "test-connect-001", + "created_time": 1769087900, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Cancel", + "by": "did:web:vasp-a.example", + "reason": "Business relationship ended" + } +} +``` + +## Security Considerations + +- All messages MUST be sent over DIDComm encrypted channels +- DDQ access URLs SHOULD be time-limited and authenticated +- Implementations MUST verify DID signatures on all messages +- Expiration times SHOULD be enforced automatically +- Connection termination via `Cancel` MUST be honored immediately +- DDQ document checksums SHOULD be verified before use + +## Privacy Considerations + +- `Connect.purpose` is optional to protect privacy +- `Authorize.reason` for declines is optional +- `Reject.reason` is optional to protect decision-making details +- DDQ access URLs should be unique per requester when possible +- Connection status changes are bilateral (not broadcast) +- Document versions and expiry times help limit data exposure + + +## Backwards Compatibility + +### Complete Backward Compatibility + +This TAIP maintains full backward compatibility: + +1. **Existing TAP Implementations:** + - Continue working unchanged + - May ignore `Connect` messages (unknown type) + - May ignore new optional fields in `Authorize` messages + - `Authorize`, `Reject` and `Cancel` work as specified in TAIP-4 + - All existing payment/transfer flows unaffected + +2. **Detection of Support:** + - Send `Connect` message + - If receive `Authorize` or `Reject` response → counterparty supports TAIP-19 + - If no response or error → counterparty doesn't support TAIP-19 + - Fall back to manual/out-of-band connection establishment + +3. **Gradual Adoption:** + - VASPs can implement `Connect` independently + - No coordination required for rollout + - Coexists with existing TAP workflows + +## Integration with Existing TAIPs + +### TAIP-4 (Transaction Authorization Protocol) + +This TAIP reuses three existing TAIP-4 messages for connection management: +- **`Authorize`**: Extended with optional fields for connection approval +- **`Reject`**: Used as-is for connection decline +- **`Cancel`**: Used as-is for connection termination + +The message structures are identical; only the context (responding to `Connect` vs `Transfer`) differs. + +### TAIP-7 (Agent Policies) + +Connection status can be expressed as policies. Not implemented as part of this spec. For example: + +```json +{ + "@type": "RequireConnection", + "connectionTypes": ["whitelist"], + "fromAgent": "beneficiary" +} +``` + +This policy would require the beneficiary to be whitelisted before sending transfers to them. + +## References + +- [TAIP-2] Defines the TAP Message structure +- [TAIP-4] Transaction Authorization Protocol +- [TAIP-7] Agent Policies + +[TAIP-2]: ./taip-2 +[TAIP-4]: ./taip-4 +[TAIP-7]: ./taip-7 + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE). From d760e50be64afb8870b0a3a0cc56c48145ee410a Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:19:40 +0100 Subject: [PATCH 02/32] Update README with TAIP-20 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index acda339..4585b59 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ The purpose of TAIPs is to provide the community with a means to propose enhance | 15 | [Agent Connection Protocol](./TAIPs/taip-15.md) | | 16 | [Invoices](./TAIPs/taip-16.md) | | 17 | [Composable Escrow](./TAIPs/taip-17.md) | +| 20 | [Trusted Connections](./TAIPs/taip-20.md) | ## Implementation Resources From ad5a88d12aca2b141cacc8df687f75757e415e67 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:21:45 +0100 Subject: [PATCH 03/32] Update CHANGELOG with TAIP-20 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bff8b1b..7dde4e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,15 @@ This changelog focuses on: - Protocol structural changes - Breaking changes +## [Unreleased] +## [2026-01-26] + + ### Added + - TAIP-20: Trusted Connections using Connect and TAIP-4 messages + - Connect message for establishing/updating trusted relationships + - Support for DDQ exchange, mutual trust, and whitelisting workflows + +## [Released] ## [2025-11-25] ### Added From 96cd13c9b5585374341530105e8ec36b61222289 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:28:35 +0100 Subject: [PATCH 04/32] Update taip-4.md Add three optional fields to Authorize message for connection approval: - approvedTypes: Array of approved connection types - ddqDocument: DDQ document reference object - trustLevel: Trust status indicator These fields are only used when responding to Connect messages (TAIP-20). --- TAIPs/taip-4.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/TAIPs/taip-4.md b/TAIPs/taip-4.md index fdd07e8..fb2c6c5 100644 --- a/TAIPs/taip-4.md +++ b/TAIPs/taip-4.md @@ -121,6 +121,22 @@ Any agent can authorize the transaction by replying as a thread to the initial m - `amount` - OPTIONAL string with the full amount as a decimal representation of the `settlementAsset` in case it is different than the original `Payment` or `Transfer` message. - `expiry` - OPTIONAL timestamp in ISO 8601 format indicating when the authorization expires. After this time, if settlement has not occurred, the authorization should be considered invalid and settlement should not proceed. In merchant payment flows, the customer's wallet may either repeat the merchant's specified expiration time or override it with a different time. +#### Connection-Specific Fields (TAIP-20) + +When responding to `Connect` messages (see [TAIP-20]), the `Authorize` message MAY include these additional optional fields to indicate connection approval: + +- `approvedTypes` - OPTIONAL array of strings indicating which connection types were approved from the original request (e.g., `["ddq-access", "mutual-trust"]`). This field SHOULD only be present when responding to `Connect` messages. +- `ddqDocument` - OPTIONAL object containing Due Diligence Questionnaire document reference. This field SHOULD only be present when responding to `Connect` messages and granting DDQ access. Object structure: + - `documentId` - REQUIRED string unique identifier for the document + - `version` - OPTIONAL string document version + - `accessUrl` - OPTIONAL string HTTPS URL for document retrieval + - `checksum` - OPTIONAL string SHA-256 hash for integrity verification + - `expiresAt` - OPTIONAL ISO 8601 timestamp when document access expires +- `trustLevel` - OPTIONAL string indicating trust status between parties: `whitelisted`, `trusted`, `standard`, `reviewing`, or `suspended`. This field SHOULD only be present when responding to `Connect` messages. + +These connection-specific fields SHOULD be omitted when authorizing transactions (`Transfer`, `Payment`, etc.). + + By not providing a `settlementAddress` until after `Authorization`, beneficiary agents can reject incoming blockchain transactions for the first time. An example Authorization flow using two agents where the `settlementAddress` was included in the original `Transfer` message: From 0642e0b8c5a222ebee94b838b21da0396bd800e2 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:30:40 +0100 Subject: [PATCH 05/32] Update Authorize message table with TAIP-20 connection fields --- messages.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/messages.md b/messages.md index eed7f17..915b4c6 100644 --- a/messages.md +++ b/messages.md @@ -623,7 +623,7 @@ An agent can require that an end user opens up an authorization URL in a web bro ### Authorize [TAIP-4] - Review -Approves a transaction after completing compliance checks. +Approves a transaction after completing compliance checks. Can also approve connection requests (TAIP-20). | Attribute | Type | Required | Status | Description | |-----------|------|----------|---------|-------------| @@ -633,8 +633,11 @@ Approves a transaction after completing compliance checks. | settlementAsset | string | No | Review ([TAIP-4]) | Optional CAIP-19 identifier for the settlement asset | | amount | string | No | Review ([TAIP-4]) | Optional decimal amount authorized of the settlementAsset | | expiry | string | No | Review ([TAIP-4]) | ISO 8601 datetime indicating when the authorization expires | +| approvedTypes | array | No | Draft ([TAIP-20]) | Array of approved connection types (for Connect responses only) | +| ddqDocument | object | No | Draft ([TAIP-20]) | DDQ document reference object (for Connect responses only) | +| trustLevel | string | No | Draft ([TAIP-20]) | Trust status indicator (for Connect responses only) | -> **Note:** The message refers to the original Transfer message via the DIDComm `thid` (thread ID) in the message envelope. +> **Note:** The message refers to the original Transfer or Payment message via the DIDComm `thid` (thread ID) in the message envelope. When used for connections, it refers to the original Connect message. #### Examples From 085912543715528bd55c9f832e7218d76dcd3b89 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:37:39 +0100 Subject: [PATCH 06/32] Adding TAIP-20 and changes to TAIP-4 Authorize --- CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dde4e8..f6f4e19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,11 +17,18 @@ This changelog focuses on: ## [Unreleased] ## [2026-01-26] - ### Added +### Added - TAIP-20: Trusted Connections using Connect and TAIP-4 messages - Connect message for establishing/updating trusted relationships - Support for DDQ exchange, mutual trust, and whitelisting workflows +### Changed +- **TAIP-4**: Extended Authorize message with optional connection-specific fields + - Added `approvedTypes` field for indicating approved connection types + - Added `ddqDocument` field for DDQ document references + - Added `trustLevel` field for trust status indicators + - These fields are only used when responding to Connect messages (TAIP-20) + ## [Released] ## [2025-11-25] From 581dee9df0163ae5ac2aa41b6c615faaa89cfeab Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:44:10 +0100 Subject: [PATCH 07/32] Create valid-authorize-approved.json Add test vector: valid Authorize connection approval --- .../connect/valid-authorize-approved.json | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 test-vectors/connect/valid-authorize-approved.json diff --git a/test-vectors/connect/valid-authorize-approved.json b/test-vectors/connect/valid-authorize-approved.json new file mode 100644 index 0000000..f3d49f9 --- /dev/null +++ b/test-vectors/connect/valid-authorize-approved.json @@ -0,0 +1,22 @@ +{ + "id": "auth-456", + "type": "https://tap.rsvp/schema/1.0#Authorize", + "from": "did:web:vasp-b.example", + "to": ["did:web:vasp-a.example"], + "thid": "conn-123e4567-e89b-12d3-a456-426614174000", + "created_time": 1706227260, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Authorize", + "approvedTypes": ["ddq-access"], + "expiry": "2026-12-31T23:59:59Z", + "ddqDocument": { + "documentId": "ddq-uuid-789", + "version": "2024-Q4", + "accessUrl": "https://vasp-b.example/api/ddq/ddq-uuid-789", + "checksum": "sha256:abc123def456...", + "expiresAt": "2026-12-31T23:59:59Z" + }, + "trustLevel": "trusted" + } +} From 25a0e94d66bda635a9cf3b328c260e1c11ade5cc Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:44:58 +0100 Subject: [PATCH 08/32] Create valid-establish-ddq.json --- test-vectors/connect/valid-establish-ddq.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 test-vectors/connect/valid-establish-ddq.json diff --git a/test-vectors/connect/valid-establish-ddq.json b/test-vectors/connect/valid-establish-ddq.json new file mode 100644 index 0000000..51484e9 --- /dev/null +++ b/test-vectors/connect/valid-establish-ddq.json @@ -0,0 +1,15 @@ +{ + "id": "conn-123e4567-e89b-12d3-a456-426614174000", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227200, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "action": "establish", + "connectionTypes": ["ddq-access"], + "purpose": "Request DDQ access for compliance verification", + "expiry": "2026-12-31T23:59:59Z" + } +} From e5db21cd66381b46ab88746093921833aba1f5fe Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:45:31 +0100 Subject: [PATCH 09/32] Create valid-reject-declined.json --- test-vectors/connect/valid-reject-declined.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 test-vectors/connect/valid-reject-declined.json diff --git a/test-vectors/connect/valid-reject-declined.json b/test-vectors/connect/valid-reject-declined.json new file mode 100644 index 0000000..a485d3f --- /dev/null +++ b/test-vectors/connect/valid-reject-declined.json @@ -0,0 +1,13 @@ +{ + "id": "reject-789", + "type": "https://tap.rsvp/schema/1.0#Reject", + "from": "did:web:vasp-b.example", + "to": ["did:web:vasp-a.example"], + "thid": "conn-123e4567-e89b-12d3-a456-426614174000", + "created_time": 1706227260, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Reject", + "reason": "Insufficient compliance documentation provided" + } +} From a68ab8120985c06e64be03dc42b26ea2ccc8dff3 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:45:55 +0100 Subject: [PATCH 10/32] Create valid-cancel-terminated.json --- test-vectors/connect/valid-cancel-terminated.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 test-vectors/connect/valid-cancel-terminated.json diff --git a/test-vectors/connect/valid-cancel-terminated.json b/test-vectors/connect/valid-cancel-terminated.json new file mode 100644 index 0000000..322a1ea --- /dev/null +++ b/test-vectors/connect/valid-cancel-terminated.json @@ -0,0 +1,14 @@ +{ + "id": "cancel-101", + "type": "https://tap.rsvp/schema/1.0#Cancel", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "thid": "conn-123e4567-e89b-12d3-a456-426614174000", + "created_time": 1706227320, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Cancel", + "by": "did:web:vasp-a.example", + "reason": "Business relationship ended" + } +} From 2793f30127facbfd39c0ba14f2442008be53d1a4 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Mon, 26 Jan 2026 14:46:12 +0100 Subject: [PATCH 11/32] Create valid-establish-whitelist.json --- .../connect/valid-establish-whitelist.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 test-vectors/connect/valid-establish-whitelist.json diff --git a/test-vectors/connect/valid-establish-whitelist.json b/test-vectors/connect/valid-establish-whitelist.json new file mode 100644 index 0000000..92f78df --- /dev/null +++ b/test-vectors/connect/valid-establish-whitelist.json @@ -0,0 +1,15 @@ +{ + "id": "conn-234e5678-e89b-12d3-a456-426614174001", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227200, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "action": "establish", + "connectionTypes": ["mutual-trust", "whitelist"], + "purpose": "Establish mutual trust and enable straight-through processing", + "expiry": "2027-01-26T00:00:00Z" + } +} From 6901bfd218d23e9235f4021c3608d037d2a07c5c Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 10:31:43 +0100 Subject: [PATCH 12/32] Delete TAIPs/taip-20.md Remove TAIP-20 (merged into TAIP-15 with explicit connectionTypes) --- TAIPs/taip-20.md | 585 ----------------------------------------------- 1 file changed, 585 deletions(-) delete mode 100644 TAIPs/taip-20.md diff --git a/TAIPs/taip-20.md b/TAIPs/taip-20.md deleted file mode 100644 index 36db164..0000000 --- a/TAIPs/taip-20.md +++ /dev/null @@ -1,585 +0,0 @@ ---- -taip: 20 -title: Connections -status: Draft -type: Standard -author: Pelle Braendgaard , Martin de Jonge -created: 2026-01-26 -requires: 2, 4, 5 ---- - -## Simple Summary -A standardized way for Entities to establish trusted connections, exchange DDQ documents, and signal mutual trust relationships. This TAIP introduces one new `Connect` message and reuses three existing TAIP-4 messages (`Authorize` for approval, `Reject` for decline, `Cancel` for termination). - -## Abstract -This TAIP extends the existing TAP protocol with a `Connect` message type for establishing trusted connections between VASPs, and leverages the existing `Authorize`, `Reject`, `Cancel` messages from TAIP-4 to manage DDQ access, mutual trust relationships, and whitelisting capabilities. This approach minimizes new message types and builds on established TAP patterns. -Within the connections the protocol establishes different connection types, which differ in trust level: -**ddq-access**: View DDQ documents -**mutual-trust**: Established trust relationship, but transactions still reviewed individually -**whitelist**: Pre-approved automatic transaction processing (typically requires mutual-trust first) -Typical progression: **ddq-access → mutual-trust → whitelist** - -## Motivation - -This adds to TAP a standardized way for establishing pre-approved trusted connections. This TAIP: -- Introduces one new message type (`Connect`) for relationship establishment -- Reuses existing message types from TAIP-4 for all approval/denial flows -- Extends the semantic meaning of `Authorize`, `Reject`, `Cancel` to cover non-payment authorization scenarios -- Provides a foundation for DDQ exchange, mutual trust, and whitelisting - -## Specification - -### New Message Type: Connect - -#### Connect Message Body - -The `Connect` message body contains: - -- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` -- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Connect` -- `action` - REQUIRED string indicating the connection action: `establish` or `update` (use Cancel from TAIP-4 to terminate connections) -- `connectionTypes` - REQUIRED (for establish/update) array of strings specifying requested connection types: `ddq-access`, `mutual-trust`, `whitelist` -- `purpose` - OPTIONAL string providing human-readable reason for connection -- `expiry` - OPTIONAL ISO 8601 timestamp when connection should automatically terminate (distinct from message `expires_time`) -- `metadata` - OPTIONAL object containing additional context - -**Complete DIDComm message example:** - -```json -{ - "id": "conn-123e4567-e89b-12d3-a456-426614174000", - "type": "https://tap.rsvp/schema/1.0#Connect", - "from": "did:web:vasps.id:initiator", - "to": ["did:web:vasps.id:recipient"], - "created_time": 1769086601, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Connect", - "action": "establish", - "connectionTypes": ["ddq-access", "mutual-trust"], - "purpose": "Request DDQ access for compliance verification", - "expiry": "2026-01-26T00:00:00Z" - } -} -``` - -### Extending TAIP-4 Messages for Connections - -The existing messages from TAIP-4 are reused for connection management: - -#### Authorize - Connection Approval - -When responding to `Connect` messages with approval, use the standard `Authorize` message from TAIP-4: - -**Authorize Body Structure (from TAIP-4):** -- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` -- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Authorize` -- `settlementAddress` - OPTIONAL (omitted for connection responses) -- `settlementAsset` - OPTIONAL (omitted for connection responses) -- `amount` - OPTIONAL (omitted for connection responses) -- `expiry` - OPTIONAL ISO 8601 timestamp when the connection authorization expires - -**Connection-Specific Attributes (new, added to body):** -- `approvedTypes` - OPTIONAL array of approved connection types (subset of requested types) -- `ddqDocument` - OPTIONAL object containing DDQ document reference (see below) -- `trustLevel` - OPTIONAL string: `whitelisted`, `trusted`, `standard`, `reviewing`, or `suspended` - -**DDQ Document Object Structure:** -- `documentId` - REQUIRED string unique identifier for the document -- `version` - OPTIONAL string document version -- `accessUrl` - OPTIONAL string HTTPS URL for document retrieval -- `checksum` - OPTIONAL string SHA-256 hash for integrity verification -- `expiresAt` - OPTIONAL ISO 8601 timestamp when document access expires - -**Complete approval example:** - -```json -{ - "id": "auth-456", - "type": "https://tap.rsvp/schema/1.0#Authorize", - "from": "did:web:vasps.id:recipient", - "to": ["did:web:vasps.id:initiator"], - "thid": "conn-123e4567-e89b-12d3-a456-426614174000", - "created_time": 1769087421, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Authorize", - "approvedTypes": ["ddq-access", "mutual-trust"], - "expiry": "2026-01-26T00:00:00Z", - "ddqDocument": { - "documentId": "ddq-uuid-789", - "version": "2024-Q4", - "accessUrl": "https://vasps.id/api/ddq/ddq-uuid-789", - "checksum": "sha256:abc123...", - "expiresAt": "2026-12-31T23:59:59Z" - }, - "trustLevel": "trusted" - } -} -``` - -#### Reject - Connection Declined - -When declining a `Connect` request, use the standard `Reject` message from TAIP-4: - -**Reject Body Structure (from TAIP-4):** -- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` -- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Reject` -- `reason` - OPTIONAL string explaining the rejection - -**Complete rejection example:** - -```json -{ - "id": "reject-789", - "type": "https://tap.rsvp/schema/1.0#Reject", - "from": "did:web:vasps.id:recipient", - "to": ["did:web:vasps.id:initiator"], - "thid": "conn-123e4567-e89b-12d3-a456-426614174000", - "created_time": 1769087421, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Reject", - "reason": "Insufficient compliance documentation" - } -} -``` - -#### Cancel - Connection Termination - -To terminate an existing connection, use the standard `Cancel` message from TAIP-4: - -**Cancel Body Structure (from TAIP-4):** -- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` -- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Cancel` -- `by` - REQUIRED in TAIP-4 for transactions to specify which party (e.g., "originator" or "beneficiary") is canceling. For connections, this can be set to the sender's DID or a simple identifier like "initiator" or "recipient" since the `from` field already identifies the canceling party. -- `reason` - OPTIONAL string explaining the cancellation - -**Complete cancellation example:** - -```json -{ - "id": "cancel-101", - "type": "https://tap.rsvp/schema/1.0#Cancel", - "from": "did:web:vasps.id:initiator", - "to": ["did:web:vasps.id:recipient"], - "thid": "conn-123e4567-e89b-12d3-a456-426614174000", - "created_time": 1769087900, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Cancel", - "by": "did:web:vasps.id:initiator", - "reason": "Business relationship ended" - } -} -``` - -**Note on `by` field for connections:** While TAIP-4 requires the `by` field to specify which party is canceling a transaction (e.g., "originator" or "beneficiary"), connections don't have these predefined roles. For connection cancellations, implementations MAY set `by` to the sender's DID (matching the `from` field) or use simple identifiers like "initiator" or "recipient". The `from` field in the message envelope is sufficient to identify who is terminating the connection. - -### Connection Types - -The protocol defines three primary connection types: - -1. **`ddq-access`**: Grants access to view DDQ documents - - Allows one party to retrieve the other's Due Diligence Questionnaire - - Can be one-way (requester views owner's DDQ) or mutual - - Example: "We can see each other's compliance documentation" - -2. **`mutual-trust`**: Establishes bilateral trust relationship for compliance purposes - - Both parties acknowledge each other as verified entities - - Reduces verification requirements but transactions still reviewed - - Enables information sharing beyond DDQ - - Example: "We've completed due diligence on each other" - -3. **`whitelist`**: Enables pre-approved, straight-through transaction processing - - Transactions from whitelisted parties proceed with minimal friction - - Automatic approval for transactions (within agreed parameters) - - Typically requires `mutual-trust` to be established first - - Example: "Transactions from this counterparty are auto-approved" - -**Typical progression:** `ddq-access` → `mutual-trust` → `whitelist` - -## Workflows - -### Establishing DDQ Access Connection - -``` -Requester Owner - | | - |--Connect------------------------->| - | (action: establish, | - | connectionTypes: [ddq-access]) | - | | - |<--Authorize----------------------| - | (approvedTypes: [ddq-access], | - | ddqDocument: {...}) | - | | -``` - -### Declining Connection Request - -``` -Requester Owner - | | - |--Connect------------------------->| - | (action: establish) | - | | - |<--Reject-------------------------| - | (reason: "...") | - | | -``` - -### Mutual Whitelisting - -``` -Party A Party B - | | - |--Connect------------------------->| - | (action: establish, | - | connectionTypes: | - | [mutual-trust, whitelist]) | - | | - |<--Authorize----------------------| - | (approvedTypes: | - | [mutual-trust, whitelist], | - | trustLevel: whitelisted) | - | | - |<-Connect-------------------------| - | (action: establish, | - | connectionTypes: | - | [mutual-trust, whitelist]) | - | | - |--Authorize----------------------->| - | (approvedTypes: | - | [mutual-trust, whitelist], | - | trustLevel: whitelisted) | - | | -``` - -### Updating Connection - -``` -Party A Party B - | | - |--Connect------------------------->| - | (action: update, | - | connectionTypes: [whitelist]) | - | [adding whitelist to existing | - | mutual-trust connection] | - | | - |<--Authorize----------------------| - | (approvedTypes: | - | [mutual-trust, whitelist]) | - | | -``` - -### Terminating Connection - -Either party can terminate a connection by sending `Cancel` (from TAIP-4): - -``` -Either Party Other Party - | | - |--Cancel-------------------------->| - | (by: sender's DID or role, | - | reason: "...") | - | | -``` - -Note: When terminating via `Cancel`, the `thid` should reference the original `Connect` message that established the connection. The `by` field can be set to the sender's DID or a simple identifier since connections don't have predefined party roles like transactions do. - -### Requesting Updated DDQ Document - -After a connection is established, a party can request document updates by sending a new `Connect` with `action: update`: - -``` -Requester Owner - | | - |--Connect------------------------->| - | (action: update, | - | connectionTypes: [ddq-access], | - | purpose: "request updated DDQ")| - | | - |<--Authorize----------------------| - | (approvedTypes: [ddq-access], | - | ddqDocument: { | - | documentId: "new-uuid", | - | version: "2025-Q1"}) | - | | -``` - -## Impact Analysis - -### TAIP-4 Changes - -**✅ NO BREAKING CHANGES** - -All existing TAIP-4 message structures remain valid and unchanged. - -**What's Being Extended:** - -1. **Semantic Extension**: `Authorize` can now respond to `Connect` messages (in addition to `Transfer`, `Payment`, etc.) -2. **Optional New Fields**: New optional fields added to `Authorize` body for connection scenarios -3. **Backward Compatible**: Existing TAIP-4 implementations ignore unknown fields - -**Existing TAIP-4 Fields (All Unchanged):** -- ✅ `@context` (REQUIRED) - Still `https://tap.rsvp/schema/1.0` -- ✅ `@type` (REQUIRED) - Still `https://tap.rsvp/schema/1.0#Authorize` -- ✅ `settlementAddress` (OPTIONAL) - Unchanged, omitted for connections -- ✅ `settlementAsset` (OPTIONAL) - Unchanged, omitted for connections -- ✅ `amount` (OPTIONAL) - Unchanged, omitted for connections -- ✅ `expiry` (OPTIONAL) - Unchanged, reused for connection expiry - -**New Optional Fields (Added to Authorize body):** -- ➕ `approvedTypes` (OPTIONAL) - Array of approved connection types -- ➕ `ddqDocument` (OPTIONAL) - Object with DDQ document details -- ➕ `trustLevel` (OPTIONAL) - Trust status indicator - -**Note**: Removed `connectionStatus` and `reason` fields - use existing TAIP-4 message types instead: -- Use `Reject` message (not Authorize) to decline connections -- Use `Cancel` message to terminate connections - -### New Additions - -**New Message Type:** -- `Connect`: New top-level message type - -**Connect Message Mandatory Fields:** -- ✅ `@context` (REQUIRED) -- ✅ `@type` (REQUIRED) -- ✅ `action` (REQUIRED) - Must be `establish` or `update` -- ✅ `connectionTypes` (REQUIRED - Must be `ddq-access`, `mutual-trust`, `whitelist` - - -## State Management - -Implementations SHOULD maintain a local `trusted_connections` table: - -```typescript -interface TrustedConnection { - connectionId: string; - counterpartyDid: string; - connectionTypes: string[]; - status: 'PENDING' | 'APPROVED' | 'DECLINED' | 'REVOKED'; - createdAt: Date; - updatedAt: Date; - expiresAt?: Date; - - // Link to most recent Connect message - connectMessageId: string; - - // Link to most recent Authorize response - authorizeMessageId?: string; - - // DDQ document details (if ddq-access granted) - ddqDocumentId?: string; - ddqAccessUrl?: string; - ddqExpiresAt?: Date; - - // Trust level - trustLevel?: string; - - metadata?: Record; -} -``` - -### Processing Connect Messages - -When receiving a `Connect` message: - -1. Validate the message structure and `action` field -2. For `action: establish`: - - Create new `trusted_connections` entry with status PENDING - - Evaluate connection request based on internal policies -3. For `action: update`: - - Locate existing connection - - Evaluate requested changes -4. Respond with appropriate message: - - **Approve**: Send `Authorize` with `approvedTypes`, optional `ddqDocument`, and `trustLevel` - - **Decline**: Send `Reject` with optional `reason` - -### Processing Authorize/Reject/Cancel Responses - -When receiving a response to your `Connect`: - -**For Authorize responses:** -1. Locate corresponding `trusted_connections` entry via `thid` -2. Update status to APPROVED -3. Store `approvedTypes` array -4. If `ddqDocument` present, store document access details -5. If `trustLevel` present, store trust status -6. Update `expiresAt` from `expiry` field if provided - -**For Reject responses:** -1. Locate corresponding `trusted_connections` entry via `thid` -2. Update status to DECLINED -3. Store optional `reason` -4. Mark connection as not available - -**For Cancel messages:** -1. Locate corresponding `trusted_connections` entry via `thid` -2. Update status to REVOKED -3. Remove access permissions -4. Archive connection record - - -## Test Cases - -### Valid Connect - Establish - -```json -{ - "id": "test-connect-001", - "type": "https://tap.rsvp/schema/1.0#Connect", - "from": "did:web:vasp-a.example", - "to": ["did:web:vasp-b.example"], - "created_time": 1769086601, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Connect", - "action": "establish", - "connectionTypes": ["ddq-access"] - } -} -``` - -### Valid Authorize - Connection Approved - -```json -{ - "id": "test-auth-001", - "type": "https://tap.rsvp/schema/1.0#Authorize", - "from": "did:web:vasp-b.example", - "to": ["did:web:vasp-a.example"], - "thid": "test-connect-001", - "created_time": 1769087421, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Authorize", - "approvedTypes": ["ddq-access"], - "ddqDocument": { - "documentId": "ddq-12345", - "accessUrl": "https://vasp-b.example/api/ddq/ddq-12345" - } - } -} -``` - -### Valid Reject - Connection Declined - -```json -{ - "id": "test-reject-001", - "type": "https://tap.rsvp/schema/1.0#Reject", - "from": "did:web:vasp-b.example", - "to": ["did:web:vasp-a.example"], - "thid": "test-connect-001", - "created_time": 1769087421, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Reject", - "reason": "Insufficient compliance documentation" - } -} -``` - -### Valid Cancel - Connection Terminated - -```json -{ - "id": "test-cancel-001", - "type": "https://tap.rsvp/schema/1.0#Cancel", - "from": "did:web:vasp-a.example", - "to": ["did:web:vasp-b.example"], - "thid": "test-connect-001", - "created_time": 1769087900, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Cancel", - "by": "did:web:vasp-a.example", - "reason": "Business relationship ended" - } -} -``` - -## Security Considerations - -- All messages MUST be sent over DIDComm encrypted channels -- DDQ access URLs SHOULD be time-limited and authenticated -- Implementations MUST verify DID signatures on all messages -- Expiration times SHOULD be enforced automatically -- Connection termination via `Cancel` MUST be honored immediately -- DDQ document checksums SHOULD be verified before use - -## Privacy Considerations - -- `Connect.purpose` is optional to protect privacy -- `Authorize.reason` for declines is optional -- `Reject.reason` is optional to protect decision-making details -- DDQ access URLs should be unique per requester when possible -- Connection status changes are bilateral (not broadcast) -- Document versions and expiry times help limit data exposure - - -## Backwards Compatibility - -### Complete Backward Compatibility - -This TAIP maintains full backward compatibility: - -1. **Existing TAP Implementations:** - - Continue working unchanged - - May ignore `Connect` messages (unknown type) - - May ignore new optional fields in `Authorize` messages - - `Authorize`, `Reject` and `Cancel` work as specified in TAIP-4 - - All existing payment/transfer flows unaffected - -2. **Detection of Support:** - - Send `Connect` message - - If receive `Authorize` or `Reject` response → counterparty supports TAIP-19 - - If no response or error → counterparty doesn't support TAIP-19 - - Fall back to manual/out-of-band connection establishment - -3. **Gradual Adoption:** - - VASPs can implement `Connect` independently - - No coordination required for rollout - - Coexists with existing TAP workflows - -## Integration with Existing TAIPs - -### TAIP-4 (Transaction Authorization Protocol) - -This TAIP reuses three existing TAIP-4 messages for connection management: -- **`Authorize`**: Extended with optional fields for connection approval -- **`Reject`**: Used as-is for connection decline -- **`Cancel`**: Used as-is for connection termination - -The message structures are identical; only the context (responding to `Connect` vs `Transfer`) differs. - -### TAIP-7 (Agent Policies) - -Connection status can be expressed as policies. Not implemented as part of this spec. For example: - -```json -{ - "@type": "RequireConnection", - "connectionTypes": ["whitelist"], - "fromAgent": "beneficiary" -} -``` - -This policy would require the beneficiary to be whitelisted before sending transfers to them. - -## References - -- [TAIP-2] Defines the TAP Message structure -- [TAIP-4] Transaction Authorization Protocol -- [TAIP-7] Agent Policies - -[TAIP-2]: ./taip-2 -[TAIP-4]: ./taip-4 -[TAIP-7]: ./taip-7 - -## Copyright - -Copyright and related rights waived via [CC0](../LICENSE). From 8643a3c0fe77c7600e37e96b9a0796b5e3743b94 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 12:46:31 +0100 Subject: [PATCH 13/32] TAIP-15: Add explicit connectionTypes as primary discriminator BREAKING CHANGES: - Added REQUIRED connectionTypes field for all connections - Transactional connections now explicitly declare ["transaction"] - Added trust connection types: ddq-access, mutual-trust, whitelist - Extended Authorize with trust-specific response fields Design rationale: - Explicit type declaration follows industry standards - Better validation and error messages - Self-documenting and easier to extend - Aligns with JSON-LD, OpenAPI, GraphQL patterns Migration: Add connectionTypes: ["transaction"] to existing Connect messages --- TAIPs/taip-15.md | 581 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 439 insertions(+), 142 deletions(-) diff --git a/TAIPs/taip-15.md b/TAIPs/taip-15.md index c5cb802..2e6e9c8 100644 --- a/TAIPs/taip-15.md +++ b/TAIPs/taip-15.md @@ -3,29 +3,41 @@ taip: 15 title: Agent Connection Protocol status: Review type: Standard -author: Pelle Braendgaard +author: Pelle Braendgaard , Martin de Jonge created: 2024-03-21 -updated: 2025-08-23 -description: Establishes a protocol for creating secure, authorized connections between TAP agents with predefined transaction constraints and OAuth-style authorization flows. Enables persistent B2B integrations with transaction limits, purpose restrictions, and user control mechanisms for ongoing business relationships while maintaining robust risk management. +updated: 2025-08-23/2026-01-28 +description: Establishes a protocol for creating secure, authorized connections between TAP agents with support for both transactional relationships (with constraints) and institutional trust relationships (DDQ exchange, whitelisting). Enables persistent B2B integrations, recurring billing, and VASP-to-VASP trust establishment. requires: [2, 4, 6, 9, 13] --- ## Simple Summary -A standard protocol for establishing secure, authorized connections between agents in the Transaction Authorization Protocol ecosystem, with support for OAuth-style authorization flows and transaction constraints. +A standard protocol for establishing secure, authorized connections between agents in the Transaction Authorization Protocol ecosystem, supporting both transactional relationships (with OAuth-style authorization and constraints) and institutional trust relationships (DDQ exchange, mutual trust, whitelisting). + ## Abstract -This TAIP defines a protocol for agents to establish secure, authorized connections with each other, particularly for ongoing business relationships like agentic initiated transaction workflows as well as recurring and metered billing. It builds on [TAIP-2] messaging, [TAIP-9] relationship proofs, and [TAIP-13] purpose codes to provide a standardized way for agents to request and authorize connections with transaction constraints. The protocol includes OAuth-style authorization flows, allowing interactive user consent when needed, and supports defining transaction limits and allowed purposes upfront. +This TAIP defines a protocol for agents to establish secure, authorized connections with each other. It supports two primary connection models: + +Transactional Connections: For ongoing business relationships like AI agent transactions, recurring billing, and B2B payment automation. These connections establish principal-agent relationships with transaction constraints (limits, purposes, allowed parties). +Trust Connections: For institutional relationships between VASPs, including DDQ (Due Diligence Questionnaire) exchange, mutual trust establishment, and whitelisting for straight-through processing. + +The protocol builds on TAIP-2 messaging, TAIP-4 authorization, TAIP-6 parties, and TAIP-13 purpose codes to provide a standardized way for agents to request and authorize connections. ## Motivation -The Transaction Authorization Protocol enables secure communication between different agents (AI Agents, VASPs, wallets, custodians, etc.). However, for ongoing business relationships, agents need a way to establish persistent, authorized connections with predefined constraints. Current implementations often rely on ad-hoc methods or require repeated authorizations. This TAIP addresses several key needs: +The Transaction Authorization Protocol enables secure communication between different agents (AI Agents, VASPs, wallets, custodians, etc.). However, for ongoing relationships, agents need ways to establish persistent, authorized connections. This TAIP addresses two distinct needs: +**Trust Connection Use Cases:** +1. **DDQ Exchange:** VASPs sharing Due Diligence Questionnaires for compliance +2. **Mutual Trust Establishment:** Bilateral verification and relationship building +3. **Whitelisting:** Pre-approved counterparties for straight-through processing +4. **Compliance Workflows:** Streamlined transaction processing between trusted parties + +**Transactional Connection Use Cases:** 1. **AI Agent Transactions:** Autonomous AI agents executing trades, payments, or financial operations within user-defined limits and purposes (e.g., trading bot with $10k daily limit for crypto arbitrage). 2. **Subscription & Recurring Payments:** SaaS platforms, streaming services, and membership organizations collecting recurring fees (e.g., monthly Netflix subscription, annual software licenses, usage-based cloud billing). 3. **Self-Onboarding Services:** Entities directly onboarding with service providers where the agent and principal are the same party (e.g., a merchant directly connecting to a payment processor's API, a business self-registering with a financial platform). - 4. **Corporate Treasury Management:** CFO tools and treasury platforms managing cash flows, vendor payments, and payroll on behalf of businesses (e.g., automated supplier payments, cross-border payroll processing). 5. **Expense Management Systems:** Corporate payment wallet programs and expense platforms processing employee reimbursements and vendor payments (e.g., Expensify submitting reimbursements, Ramp processing corporate card settlements). 6. **Marketplace & Platform Payouts:** E-commerce platforms, gig economy apps, and creator platforms distributing earnings (e.g., Shopify merchant payouts, Uber driver payments, YouTube creator revenue sharing). @@ -33,17 +45,92 @@ The Transaction Authorization Protocol enables secure communication between diff 8. **Cross-Border Payment Services:** International payment providers and remittance services executing FX conversions and transfers (e.g., Wise business accounts, payroll providers handling multi-currency payments). 9. **DeFi Protocol Integration:** Decentralized protocols performing automated yield farming, liquidity provision, or collateral management (e.g., auto-compounding vaults, algorithmic trading strategies). -By standardizing these connection aspects, we enable secure B2B integrations while maintaining user control and risk management. Each connection enforces specific constraints including transaction limits, allowed purposes, and time boundaries. + By standardizing these connection aspects, we enable secure B2B integrations while maintaining user control and risk management. Each Transactional connection enforces specific constraints including transaction limits, allowed purposes, and time boundaries. ## Specification ### Message Types -All messages implement [TAIP-2] and are sent between [TAIP-5 Agents][TAIP-5]. Each message type has specific requirements for its body object. The principal-agent relationship follows the model defined in [TAIP-6], where agents act on behalf of real-world parties. +All messages implement [TAIP-2] and are sent between [TAIP-5 Agents][TAIP-5]. + +### Connect Message + +A message sent to establish or update a connection between agents. + +#### All Connections (Required) + +- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` +- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Connect` +- `connectionTypes` - REQUIRED array of strings specifying the connection types being requested. Must contain at least one of: + - `transaction` - For transactional connections (B2B integrations, recurring billing, transaction authorization) + - `ddq-access` - For DDQ document exchange between institutions + - `mutual-trust` - For establishing bilateral trust relationships + - `whitelist` - For enabling pre-approved straight-through processing +- `purpose` - OPTIONAL string human-readable purpose for the connection +- `expiry` - OPTIONAL ISO 8601 timestamp when the connection request expires +- `agreement` - OPTIONAL string URL pointing to terms of service or agreement + +#### Trust Connection Fields + +Used when `connectionTypes` includes trust-related types (`ddq-access`, `mutual-trust`, `whitelist`): + +- `action` - OPTIONAL string indicating connection lifecycle action: `establish` (default) or `update` +- `attachments` - OPTIONAL array of [TAIP-2] message attachments. Can include DDQ documents or other supporting materials. When present, these documents are provided inline for review during connection establishment. + +**Note**: Trust connections SHOULD NOT include `requester`, `principal`, `agents`, or `constraints` fields. These are peer-to-peer institutional relationships. + +**Attachment Usage**: Trust connections can use attachments to provide documents inline (e.g., DDQ PDFs, compliance certificates). The `ddqDocument` field in Authorize responses provides URLs for later retrieval, while attachments provide immediate document access during connection establishment. + +## Trust Connection Types + +### transaction +Establishes a transactional connection for ongoing business relationships. Requires principal-agent relationship with transaction constraints. + +**Typical use**: B2B integrations, recurring billing, AI agent transactions, expense management + +**Required fields**: `requester`, `principal`, `agents`, `constraints` + +### ddq-access +Grants access to view DDQ documents. Enables one party to retrieve the other's Due Diligence Questionnaire for compliance verification. + +**Typical use**: Initial relationship establishment, periodic compliance reviews + +### mutual-trust +Establishes bilateral trust relationship. Both parties acknowledge each other as verified entities, reducing verification requirements but transactions still undergo review. -### Parties and Agent Roles +**Typical use**: Post-DDQ review, established business relationships -The Agent Connection Protocol involves two distinct parties and their respective agents: +### whitelist +Enables pre-approved, straight-through transaction processing. Transactions from whitelisted parties proceed with minimal friction and automatic approval within agreed parameters. + +**Typical use**: High-volume trusted counterparties, routine business operations + +**Typical trust progression**: ddq-access → mutual-trust → whitelist + +#### Transactional Connection Fields + +REQUIRED when `connectionTypes` includes `"transaction"`: + +- `requester` - REQUIRED [TAIP-6] Party object representing the party requesting the connection + - `@id` - REQUIRED string DID or IRI of the requesting party +- `principal` - REQUIRED [TAIP-6] Party object representing the party on whose behalf transactions will be performed + - `@id` - REQUIRED string DID or IRI of the principal party +- `agents` - REQUIRED array of agent objects representing agents involved. Must include at least one agent whose `@id` matches the DIDComm `from` field with `for` attribute set to requester DID +- `constraints` - REQUIRED object specifying transaction constraints: + - `purposes` - OPTIONAL array of [TAIP-13] purpose codes + - `categoryPurposes` - OPTIONAL array of [TAIP-13] category purpose codes + - `limits` - OPTIONAL object containing transaction limits: + - `per_transaction`, `per_day`, `per_week`, `per_month`, `per_year` - OPTIONAL string decimal amounts + - `currency` - REQUIRED string ISO 4217 currency code if limits specified + - `allowedBeneficiaries` - OPTIONAL array of [TAIP-6] Party objects + - `allowedSettlementAddresses` - OPTIONAL array of [CAIP-10] addresses + - `allowedAssets` - OPTIONAL array of [CAIP-19] asset identifiers +- `attachments` - OPTIONAL array of transaction messages (Transfer, Payment) for immediate authorization + + +##### Parties and Agent Roles + +The Agent Connection Protocol for Transaction connections involves two distinct parties and their respective agents: **Requester Party**: The party that initiates the connection request. This is typically a service provider, merchant, or other entity seeking permission to perform transactions on behalf of or with another party. The requester party is represented by one or more agents that handle the technical aspects of the connection process. @@ -57,9 +144,11 @@ The Agent Connection Protocol involves two distinct parties and their respective This separation allows for complex B2B relationships where a service provider (requester) wants to act on behalf of their customer (principal) while maintaining clear accountability and authorization chains. -### Transaction Constraints +**Note:** This party-agent model applies to transactional connections only. Trust connections are peer-to-peer institutional relationships without requester/principal distinction. + +## Transaction Constraints (Transactional Connections) -Transaction constraints are a fundamental security mechanism in the Agent Connection Protocol that define the boundaries and permissions for transactions performed through an established connection. These constraints serve multiple critical purposes: +Transaction constraints are a fundamental security mechanism in transactional connections that define the boundaries and permissions for transactions performed through an established connection. These constraints serve multiple critical purposes: **Security and Risk Management**: Constraints act as guardrails that prevent unauthorized or excessive transactions, protecting both parties from potential fraud, errors, or misuse of the connection. They establish clear limits on transaction amounts, frequencies, and purposes. @@ -69,7 +158,7 @@ Transaction constraints are a fundamental security mechanism in the Agent Connec **Automated Decision Making**: Constraints enable receiving agents to automatically approve transactions that fall within established parameters while flagging or rejecting those that exceed the agreed-upon limits. -#### Constraint Enforcement +### Constraint Enforcement Agents MUST enforce all specified constraints when processing transactions through an established connection. Failure to respect constraints constitutes a violation of the connection agreement and may result in: - Transaction rejection @@ -77,7 +166,7 @@ Agents MUST enforce all specified constraints when processing transactions throu - Loss of trust between parties - Potential legal or regulatory consequences -#### Types of Constraints +### Types of Constraints The Agent Connection Protocol supports several categories of transaction constraints: @@ -99,118 +188,83 @@ The Agent Connection Protocol supports several categories of transaction constra - `allowedAssets` - Specific [CAIP-19] assets that can be transacted through this connection - These constraints enable precise control over which tokens and addresses can be used -Constraints work together to create a comprehensive authorization framework. For example, a connection might allow monthly subscription payments (`purposes: ["SUBS"]`) up to $100 per month (`limits: {"per_month": "100.00", "currency": "USD"}`) only to a specific merchant (`allowedBeneficiaries: [{"@id": "did:web:saas-provider.example"}]`) using only USDC tokens (`allowedAssets: ["eip155:1/erc20:0xA0b86a33E6441b7178bb7094b2c4b6e5066d68B7"]`). +Constraints work together to create a comprehensive authorization framework. For example, a transactional connection might allow monthly subscription payments (`purposes: ["SUBS"]`) up to $100 per month (`limits: {"per_month": "100.00", "currency": "USD"}`) only to a specific merchant (`allowedBeneficiaries: [{"@id": "did:web:saas-provider.example"}]`) using only USDC tokens (`allowedAssets: ["eip155:1/erc20:0xA0b86a33E6441b7178bb7094b2c4b6e5066d68B7"]`). -### Connect Message -A message sent by an agent requesting connection to another agent: +### Response Messages -- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` -- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Connect` -- `requester` - REQUIRED [TAIP-6] Party object representing the party requesting the connection: - - `@id` - REQUIRED string DID or IRI of the requesting party - - Additional attributes MAY be included as defined in [TAIP-6], such as country code, merchant category code, or other party metadata -- `principal` - REQUIRED [TAIP-6] Party object representing the party the requesting agent acts on behalf of: - - `@id` - REQUIRED string DID or IRI of the principal party - - Additional attributes MAY be included as defined in [TAIP-6], such as country code, merchant category code, or other party metadata -- `agents` - REQUIRED array of agent objects representing agents involved in the connection process. Each agent object follows [TAIP-5] specification. At minimum, there MUST be one agent in this array whose `@id` matches the `from` field of the surrounding DIDComm message and has a `for` attribute set to the `requester` DID -- `constraints` - REQUIRED object specifying the requested transaction constraints: - - `purposes` - OPTIONAL array of [TAIP-13] purpose codes - - `categoryPurposes` - OPTIONAL array of [TAIP-13] category purpose codes - - `limits` - OPTIONAL object containing transaction limits: - - `per_transaction` - OPTIONAL string decimal amount - - `per_day` - OPTIONAL string decimal amount - - `per_week` - OPTIONAL string decimal amount - - `per_month` - OPTIONAL string decimal amount - - `per_year` - OPTIONAL string decimal amount - - `currency` - REQUIRED string ISO 4217 currency code if limits are specified - - `allowedBeneficiaries` - OPTIONAL array of [TAIP-6] Party objects representing parties that can receive payments through this connection - - `allowedSettlementAddresses` - OPTIONAL array of [CAIP-10] addresses that are permitted for settlement through this connection - - `allowedAssets` - OPTIONAL array of [CAIP-19] asset identifiers that can be transacted through this connection -- `agreement` - OPTIONAL string URL pointing to terms of service or agreement between the principal and requesting agent -- `expiry` - OPTIONAL timestamp in ISO 8601 format indicating when the connection request expires. After this time, if no authorization has occurred, the connection request should be considered invalid. This is distinct from the technical message expiry handled by the DIDComm `expires_time` header. -- `attachments` - OPTIONAL array of [TAIP-2] message attachments containing transaction messages (such as [TAIP-3] Transfer or [TAIP-14] Payment messages) that should be authorized in the same context as the Connect request. When attachments are present, authorization of the Connect request also authorizes the attached transaction messages. This enables use cases like establishing recurring billing connections with an immediate first payment, or setting up trading permissions with an initial transaction. All attached transaction messages MUST respect the connection's defined constraints. - -### AuthorizationRequired Message - -A message sent in response to a Connect request when interactive authorization is needed. This message follows the specification defined in [TAIP-4] for interactive authorization flows. +#### Authorize Message (Connection Approval) -- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` -- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#AuthorizationRequired` -- `authorizationUrl` - REQUIRED string URL where the user can authorize the connection -- `expires` - REQUIRED string ISO 8601 timestamp when the authorization URL expires -- `from` - OPTIONAL the party type (e.g., `customer`, `principal`, or `originator`) that is required to open the URL +Response approving a connection request. Uses standard [TAIP-4] Authorize message. -For the complete specification of this message type, see [TAIP-4]. +**For Transactional Connections:** +- Standard Authorize body (no additional fields needed) +- Connection ID is the message `id` of the Connect message (referenced via `thid`) -### Authorize Message +**For Trust Connections:** +Authorize body includes additional optional fields: -A message sent to approve a connection request: +- `approvedTypes` - OPTIONAL array of approved connection types (subset of requested) +- `ddqDocument` - OPTIONAL object containing DDQ document reference: + - `documentId` - REQUIRED string unique identifier + - `version` - OPTIONAL string document version + - `accessUrl` - OPTIONAL string HTTPS URL for retrieval + - `checksum` - OPTIONAL string SHA-256 hash + - `expiresAt` - OPTIONAL ISO 8601 timestamp when access expires +- `trustLevel` - OPTIONAL string: `whitelisted`, `trusted`, `standard`, `reviewing`, `suspended` -- `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` -- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Authorize` +**Example Trust Connection Approval:** + +```json +{ + "id": "auth-456", + "type": "https://tap.rsvp/schema/1.0#Authorize", + "from": "did:web:vasp-b.example", + "to": ["did:web:vasp-a.example"], + "thid": "conn-123", + "created_time": 1706227260, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Authorize", + "approvedTypes": ["ddq-access", "mutual-trust"], + "ddqDocument": { + "documentId": "ddq-uuid-789", + "version": "2024-Q4", + "accessUrl": "https://vasp-b.example/api/ddq/ddq-uuid-789", + "expiresAt": "2026-12-31T23:59:59Z" + }, + "trustLevel": "trusted" + } +} +``` -### Reject Message +#### Reject Message -A message sent to reject a connection request: +Standard [TAIP-4] Reject message to decline connection: - `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` - `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Reject` -- `reason` - OPTIONAL string human-readable reason for rejection +- `reason` - OPTIONAL string explaining rejection -### Cancel Message +#### Cancel Message -A message sent by principal to terminate an existing connection: +Standard [TAIP-4] Cancel message to terminate connection: - `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` - `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#Cancel` -- `by` - REQUIRED should be `principal` -- `reason` - OPTIONAL string human-readable reason for cancellation +- `by` - REQUIRED the party terminating connection (for transactional: "principal" or "requester"; for trust: sender's DID) +- `reason` - OPTIONAL string explaining cancellation -### AddAgents Message +#### AuthorizationRequired Message -A message sent to add additional agents to the connection process as defined in [TAIP-5]. This is particularly useful for adding the principal's agent after the initial Connect request: +For transactional connections requiring interactive authorization. Standard [TAIP-4] message: - `@context` - REQUIRED the JSON-LD context `https://tap.rsvp/schema/1.0` -- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#AddAgents` -- `agents` - REQUIRED an array of agent objects to add to the connection. Each agent object follows [TAIP-5] specification - -For complete specification of this message type, see [TAIP-5]. - -### Connection Flow - -1. Agent A sends Connect message to Agent B with: - - The requesting party's identity - - The principal party they represent - - Agent identities and endpoints in the agents array - - Desired transaction constraints - - Optionally, transaction messages (Transfer, Payment, etc.) as attachments for immediate authorization - -2. Agent B chooses an authorization method: - - Option 1: Out-of-band Authorization - - Notifies customer through existing channels - - Customer logs into VASP's service to review - - Option 2: Authorization URL - - Returns AuthorizationRequired with URL - - Customer opens URL to review and authenticate - -3. Customer reviews and decides: - - Views connection details and constraints - - Reviews any attached transaction messages for immediate execution - - Approves or denies through chosen interface - -4. Agent B sends final response: - - Authorize message if approved (automatically authorizes any attached transactions) - - Reject message if denied +- `@type` - REQUIRED the JSON-LD type `https://tap.rsvp/schema/1.0#AuthorizationRequired` +- `authorizationUrl` - REQUIRED string URL for authorization +- `expires` - REQUIRED ISO 8601 timestamp when URL expires +- `from` - OPTIONAL party type requiring authorization -5. Agent addition (if needed): - - Additional agents may be added using AddAgent messages as replies to the Connect thread - - This allows the principal's agent to be included if not initially present - -6. Once authorized: - - Connection is established with a unique identifier - - Future transactions must respect the agreed constraints - - Either party can Cancel the connection ### Out-of-Band Initiation @@ -284,7 +338,100 @@ https://example.com/path?_oobid=2e9e257c-2839-4fae-b0c4-dcd4e2159f4e Where the `_oob` parameter contains the base64url-encoded Out-of-Band message, or the `_oobid` parameter contains a unique identifier that can be resolved to retrieve the full Out-of-Band message. -### Connection Flow Diagrams + +### Connection Workflows + +#### Transactional Connection Flow +Simple: +``` +Requesting Agent Principal's Agent + | | + |--Connect---------------------------->| + | (connectionTypes: [transaction], | + | requester, principal, agents, | + | constraints) | + | | + |<--AuthorizationRequired (optional)---| + | (authorizationUrl) | + | | + [Principal authorizes via URL] + | | + |<--Authorize--------------------------| + | | +``` +Full: +1. Agent A sends Connect message to Agent B with: + - The requesting party’s identity + - The principal party they represent + - Agent identities and endpoints in the agents array + - Desired transaction constraints + - Optionally, transaction messages (Transfer, Payment, etc.) as attachments for immediate authorization +2. Agent B chooses an authorization method: + - Option 1: Out-of-band Authorization + - Notifies customer through existing channels + - Customer logs into VASP’s service to review + - Option 2: Authorization URL + - Returns AuthorizationRequired with URL + - Customer opens URL to review and authenticate +3. Customer reviews and decides: + - Views connection details and constraints + - Reviews any attached transaction messages for immediate execution + - Approves or denies through chosen interface +4. Agent B sends final response: + - Authorize message if approved (automatically authorizes any attached transactions) + - Reject message if denied +5. Agent addition (if needed): + - Additional agents may be added using AddAgent messages as replies to the Connect thread + - This allows the principal’s agent to be included if not initially present +6. Once authorized: + - Connection is established with a unique identifier + - Future transactions must respect the agreed constraints + - Either party can Cancel the connection + +#### Trust Connection Flow (DDQ Access) + +``` +VASP A VASP B + | | + |--Connect---------------------------->| + | (connectionTypes: [ddq-access]) | + | | + |<--Authorize--------------------------| + | (approvedTypes: [ddq-access], | + | ddqDocument: {...}) | + | | +``` + +#### Trust Connection Update Flow + +``` +VASP A VASP B + | | + |--Connect----------------------------->| + | (action: update, | + | connectionTypes: | + | [mutual-trust, whitelist]) | + | | + |<--Authorize--------------------------| + | (approvedTypes: | + | [mutual-trust, whitelist], | + | trustLevel: whitelisted) | + | | +``` + +#### Connection Termination + +``` +Either Party Other Party + | | + |--Cancel------------------------------>| + | (by: terminating party, | + | reason: "...") | + | | +``` + + +### Extended Connection Flow Diagrams for Transactional connections #### Basic Connection Flow with Direct Authorization @@ -375,50 +522,45 @@ sequenceDiagram CustomerWallet->>PSP: Settle [settlementId] ``` -### Connection Security +## Security Considerations -- All messages MUST be encrypted using [TAIP-2] message encryption -- Agents MUST verify DIDs and signatures before accepting connections -- Authorization MUST be performed through secure, authenticated channels -- Authorization URLs MUST use HTTPS and include CSRF protection -- Connection identifiers should be unique and unpredictable -- When using `serviceUrl` in the agent object: - - The URL MUST use HTTPS for security - - Agents MUST prioritize DIDComm service endpoints from the DID document over the `serviceUrl` field - - The `serviceUrl` SHOULD only be used when no valid DIDComm service endpoint is resolvable from the DID document - - Agents SHOULD validate that the `serviceUrl` actually belongs to the DID holder through appropriate verification mechanisms +- All messages MUST be sent over DIDComm encrypted channels +- Transactional connections: Validate all transactions against constraints +- Trust connections: Verify DDQ document checksums before use +- Connection termination via Cancel MUST be honored immediately +- Expiration times SHOULD be enforced automatically -## Rationale +## Privacy Considerations -The design choices in this specification aim to balance security, usability, and flexibility: +- `purpose` field is optional to protect decision-making details +- `Reject.reason` is optional to protect internal policies +- Trust connections: DDQ access URLs should be unique per requester +- Trust connections: Connection status changes are bilateral (not broadcast) +- Transactional connections: Constraints may reveal business relationships -- **Flexible Authorization:** Supports both out-of-band and URL-based flows -- **Purpose Codes:** Uses [TAIP-13] for standardized transaction types -- **Transaction Limits:** Provides clear constraints for risk management -- **Connection Identifiers:** Enable tracking and management of approved connections -- **State Management:** Receiving agents track connection status +## Backwards Compatibility -## Security Considerations +### Breaking Changes from Previous TAIP-15 -- **Authorization Flow:** Must use secure authentication channels -- **Authorization URLs:** Must prevent CSRF and phishing attacks -- **Connection Identifiers:** Must be unique and unpredictable -- **Transaction Limits:** Must be enforced server-side -- **Connection State:** Must be securely maintained +1. **Made fields conditional**: `requester`, `principal`, `agents`, `constraints` are now REQUIRED only for transactional connections +2. **Added trust connection support**: New `connectionTypes` field and workflows +3. **Extended Authorize**: Added optional fields for trust connection approval -## Privacy Considerations +### Migration Path + +Existing TAIP-15 implementations continue to work unchanged: +- All existing transactional connections remain valid +- Fields like `requester`, `principal` are still REQUIRED for transactional use +- New trust connection features are additive (won't break existing flows) + +Implementations can detect connection type by field presence and handle accordingly. -- **Minimal Disclosure:** Only exchange necessary information -- **User Consent:** Clear authorization UI showing permissions -- **Connection Isolation:** Unique identifiers per connection -- **Data Retention:** Clear connection data when terminated -- **Audit Logs:** Balance logging with privacy ## Test Cases The following are example plaintext messages. See [TAIP-2] for how to sign the messages. -### Connect +### Transactional Connect ```json { @@ -430,6 +572,7 @@ The following are example plaintext messages. See [TAIP-2] for how to sign the m "body": { "@context": "https://tap.rsvp/schema/1.0", "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["transaction"], "requester": { "@id": "did:example:b2b-service" }, @@ -477,6 +620,93 @@ The following are example plaintext messages. See [TAIP-2] for how to sign the m } ``` +### Trust Connection: DDQ Exchange + +```json +{ + "id": "conn-ddq-456", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227200, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["ddq-access"], + "purpose": "Request DDQ access for compliance verification", + "expiry": "2026-12-31T23:59:59Z" + } +} +``` + +### Trust Connection: DDQ Exchange with Inline Document + +```json +{ + "id": "conn-ddq-789", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227200, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["ddq-access"], + "purpose": "Provide DDQ document for mutual verification", + "expiry": "2026-12-31T23:59:59Z" + }, + "attachments": [ + { + "id": "ddq-doc-1", + "description": "VASP A Due Diligence Questionnaire 2024-Q4", + "filename": "vasp-a-ddq-2024-q4.pdf", + "media_type": "application/pdf", + "data": { + "base64": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PgplbmRvYmoKMiAwIG9iago8PC9UeXBlL1BhZ2VzL0NvdW50IDEvS2lkc1szIDAgUl0+PgplbmRvYmoK..." + } + } + ] +} +``` + +### Trust Connection: Mutual Whitelisting + +```json +{ + "id": "conn-whitelist-789", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227200, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["mutual-trust", "whitelist"], + "purpose": "Establish mutual trust and enable straight-through processing", + "expiry": "2027-01-26T00:00:00Z" + } +} +``` + +### Trust Connection Update: Add Whitelist + +```json +{ + "id": "conn-update-101", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227200, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "action": "update", + "connectionTypes": ["whitelist"], + "purpose": "Upgrade to whitelisted status for high-volume processing" + } +} +``` + ### AuthorizationRequired ```json @@ -497,7 +727,7 @@ The following are example plaintext messages. See [TAIP-2] for how to sign the m } ``` -### Authorize +### Authorize Transaction ```json { @@ -514,6 +744,30 @@ The following are example plaintext messages. See [TAIP-2] for how to sign the m } ``` +### Authorize Connection +```json +{ + "id": "auth-456", + "type": "https://tap.rsvp/schema/1.0#Authorize", + "from": "did:web:vasp-b.example", + "to": ["did:web:vasp-a.example"], + "thid": "conn-123", + "created_time": 1706227260, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Authorize", + "approvedTypes": ["ddq-access", "mutual-trust"], + "ddqDocument": { + "documentId": "ddq-uuid-789", + "version": "2024-Q4", + "accessUrl": "https://vasp-b.example/api/ddq/ddq-uuid-789", + "expiresAt": "2026-12-31T23:59:59Z" + }, + "trustLevel": "trusted" + } +} +``` + ### Reject ```json @@ -601,11 +855,12 @@ In this self-onboarding case: - There is one agent representing the merchant in the `agents` array - The `agreement` field points to the merchant agreement terms -## Using Connections for Transactions +## Using Connections for Transactions +### Transactional Connections Once a connection is established, the connecting agent can perform transactions on behalf of the customer. All transactions related to a connection MUST include the connection's `id` as the `pthid` (parent thread ID) in the message header. This allows receiving agents to validate the transaction against the connection's constraints. -### Example Transfer Using Connection +### Example Transfer Using Transactional Connection The following example shows a [TAIP-3] Transfer message sent by a B2B service using their authorized connection to initiate a transfer on behalf of their customer: @@ -661,7 +916,7 @@ The receiving agent MUST: ### Example Connect with Attached Payment for Recurring Billing -The following example shows a Connect message with an attached Payment message for establishing recurring billing with an immediate first payment: +The following example shows a Transactional Connect message with an attached Payment message for establishing recurring billing with an immediate first payment: ```json { @@ -673,6 +928,7 @@ The following example shows a Connect message with an attached Payment message f "body": { "@context": "https://tap.rsvp/schema/1.0", "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["transaction"], "requester": { "@id": "did:web:saas-provider.example", "name": "SaaS Platform Inc" @@ -741,6 +997,46 @@ In this example: - Future recurring payments can reference this connection via `pthid` - The attached Payment respects the connection's constraints (amount within limits, correct purpose) +### Trust Connections + +Trust connections influence authorization behavior but don't use `pthid`. Instead, agents check trust status when authorizing transactions. + +**Example Transfer between Whitelisted VASPs:** + +```json +{ + "id": "transfer-789", + "type": "https://tap.rsvp/schema/1.0#Transfer", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227400, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Transfer", + "asset": "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "amount": "1000.00", + "originator": { + "@id": "did:example:alice" + }, + "beneficiary": { + "@id": "did:example:bob" + }, + "agents": [ + { + "@id": "did:web:vasp-a.example", + "for": "did:example:alice" + }, + { + "@id": "did:web:vasp-b.example", + "for": "did:example:bob" + } + ] + } +} +``` + +VASP B checks its trusted connections table and sees VASP A is whitelisted, enabling fast-track authorization. + ## References @@ -760,6 +1056,7 @@ In this example: [CAIP-10]: https://chainagnostic.org/CAIPs/caip-10 "Account ID Specification" [CAIP-19]: https://chainagnostic.org/CAIPs/caip-19 "Asset Type and Asset ID Specification" -## Copyright +## Citation +Please cite this document as: -Copyright and related rights waived via [CC0]. +Pelle Braendgaard, "TAIP-15: Agent Connection Protocol," Transaction Authorization Improvement Proposals, no. 15, March 2024. [Online serial]. Available: https://github.com/TransactionAuthorizationProtocol/TAIPs/blob/master/TAIPs/taip-15.md From 59eb2fe2c2ebc0ed77dd39e16e8fcd706dac8cc2 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 13:01:05 +0100 Subject: [PATCH 14/32] Update Connect message with explicit connectionTypes - Added connectionTypes as REQUIRED field for all connections - Clarified field requirements based on connection type - Added connection types table for reference - Updated documentation to reflect explicit type discrimination updated examples --- messages.md | 178 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 164 insertions(+), 14 deletions(-) diff --git a/messages.md b/messages.md index 915b4c6..241f2fe 100644 --- a/messages.md +++ b/messages.md @@ -674,6 +674,30 @@ Approves a transaction after completing compliance checks. Can also approve conn } ``` +##### Example Trust Connection Authorization +```json +{ + "id": "auth-456", + "type": "https://tap.rsvp/schema/1.0#Authorize", + "from": "did:web:vasp-b.example", + "to": ["did:web:vasp-a.example"], + "thid": "conn-123", + "created_time": 1706227260, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Authorize", + "approvedTypes": ["ddq-access", "mutual-trust"], + "ddqDocument": { + "documentId": "ddq-uuid-789", + "version": "2024-Q4", + "accessUrl": "https://vasp-b.example/api/ddq/ddq-uuid-789", + "expiresAt": "2026-12-31T23:59:59Z" + }, + "trustLevel": "trusted" + } +} +``` + ### Settle [TAIP-4] - Review @@ -1366,20 +1390,51 @@ Updates policies for a transaction. ## Connection Messages ### Connect -[TAIP-15] - Draft +[TAIP-15] - Review + +Requests a connection between agents. Supports both transactional connections (with constraints) and trust connections (DDQ, whitelisting). -Requests a connection between agents with specified constraints. +#### All Connections (Required) | Attribute | Type | Required | Status | Description | |-----------|------|----------|---------|-------------| -| @context | string | Yes | Draft ([TAIP-15]) | JSON-LD context "https://tap.rsvp/schema/1.0" | -| @type | string | Yes | Draft ([TAIP-15]) | JSON-LD type "https://tap.rsvp/schema/1.0#Connect" | -| requester | [Party](#party) | Yes | Draft ([TAIP-15]) | Party object representing the party requesting the connection | -| principal | [Party](#party) | Yes | Draft ([TAIP-15]) | Party object representing the party the requesting agent acts on behalf of | -| agents | array | Yes | Draft ([TAIP-15]) | Array of agent objects involved in the connection process | -| constraints | object | Yes | Draft ([TAIP-15]) | Transaction constraints for the connection (see [constraints table](#transaction-constraints)) | -| expiry | string | No | Draft ([TAIP-15]) | ISO 8601 datetime indicating when the connection request expires | -| agreement | string | No | Draft ([TAIP-15]) | URL or identifier of terms agreed to by the principal | +| @context | string | Yes | Review ([TAIP-15]) | JSON-LD context "https://tap.rsvp/schema/1.0" | +| @type | string | Yes | Review ([TAIP-15]) | JSON-LD type "https://tap.rsvp/schema/1.0#Connect" | +| connectionTypes | array | Yes | Review ([TAIP-15]) | Array of connection types: "transaction", "ddq-access", "mutual-trust", "whitelist" | +| purpose | string | No | Review ([TAIP-15]) | Human-readable purpose for the connection | +| expiry | string | No | Review ([TAIP-15]) | ISO 8601 datetime when connection request expires | +| agreement | string | No | Review ([TAIP-15]) | URL pointing to terms of service | + +#### Transactional Connection Fields +*(Required when connectionTypes includes "transaction")* + +| Attribute | Type | Required | Status | Description | +|-----------|------|----------|---------|-------------| +| requester | [Party](#party) | Yes* | Review ([TAIP-15]) | Party requesting the connection (*required for transaction type) | +| principal | [Party](#party) | Yes* | Review ([TAIP-15]) | Party on whose behalf transactions will be performed (*required for transaction type) | +| agents | array | Yes* | Review ([TAIP-15]) | Array of agent objects involved (*required for transaction type) | +| constraints | object | Yes* | Review ([TAIP-15]) | Transaction constraints (*required for transaction type, see [constraints table](#transaction-constraints)) | +| attachments | array | No | Review ([TAIP-15]) | Transaction messages for immediate authorization | + +#### Trust Connection Fields +*(Used when connectionTypes includes trust types)* + +| Attribute | Type | Required | Status | Description | +|-----------|------|----------|---------|-------------| +| action | string | No | Review ([TAIP-15]) | Connection action: "establish" (default) or "update" | +| attachments | array | No | Review ([TAIP-15]) | DIDComm message attachments (e.g., DDQ documents, certificates) | + +**Note:** Connection behavior is determined by `connectionTypes`. Transactional connections (`["transaction"]`) require `requester`, `principal`, `agents`, and `constraints`. Trust connections should omit these fields but MAY include attachments for inline document delivery. + +#### Connection Types + +| Value | Description | Required Fields | +|-------|-------------|-----------------| +| transaction | Transactional connections for B2B integrations, recurring billing | requester, principal, agents, constraints | +| ddq-access | DDQ document exchange between institutions | None (peer-to-peer) | +| mutual-trust | Bilateral trust relationship establishment | None (peer-to-peer) | +| whitelist | Pre-approved straight-through processing | None (peer-to-peer) | + #### Transaction Constraints @@ -1400,7 +1455,10 @@ The `constraints` object defines the boundaries and permissions for transactions | allowedSettlementAddresses | array | No | Draft ([TAIP-15]) | Array of [CAIP-10] addresses permitted for settlement | | allowedAssets | array | No | Draft ([TAIP-15]) | Array of [CAIP-19] asset identifiers that can be transacted | -#### Example Connect Message +#### Example Connect Messages + +##### Transactional Connection (B2B Payment Service) + ```json { "id": "123e4567-e89b-12d3-a456-426614174000", @@ -1412,9 +1470,10 @@ The `constraints` object defines the boundaries and permissions for transactions "body": { "@context": "https://tap.rsvp/schema/1.0", "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["transaction"], "requester": { - "@id": "did:example:business-customer", - "name": "Business Customer" + "@id": "did:example:b2b-service", + "name": "B2B Payment Service" }, "principal": { "@id": "did:example:business-customer", @@ -1425,7 +1484,7 @@ The `constraints` object defines the boundaries and permissions for transactions "@id": "did:example:b2b-service", "name": "B2B Payment Service", "serviceUrl": "https://b2b-service/did-comm", - "for": "did:example:business-customer" + "for": "did:example:b2b-service" } ], "constraints": { @@ -1460,6 +1519,97 @@ The `constraints` object defines the boundaries and permissions for transactions } ``` +##### Trust Connection (DDQ Access Request) + +```json +{ + "id": "conn-ddq-123", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227200, + "expires_time": 1706313600, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["ddq-access"], + "purpose": "Request DDQ access for compliance verification", + "expiry": "2026-12-31T23:59:59Z" + } +} +``` + +##### Trust Connection (Mutual Trust with Whitelist) + +```json +{ + "id": "conn-trust-456", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227200, + "expires_time": 1706313600, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["mutual-trust", "whitelist"], + "purpose": "Establish mutual trust and enable straight-through processing", + "expiry": "2027-01-26T00:00:00Z" + } +} +``` + +##### Trust Connection (DDQ Exchange with Inline Document) + +```json +{ + "id": "conn-ddq-789", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227200, + "expires_time": 1706313600, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["ddq-access"], + "purpose": "Provide DDQ document for mutual verification", + "expiry": "2026-12-31T23:59:59Z" + }, + "attachments": [ + { + "id": "ddq-doc-1", + "description": "VASP A Due Diligence Questionnaire 2024-Q4", + "filename": "vasp-a-ddq-2024-q4.pdf", + "media_type": "application/pdf", + "data": { + "base64": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2..." + } + } + ] +} +``` + +##### Trust Connection Update (Add Whitelist) + +```json +{ + "id": "conn-update-101", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227300, + "expires_time": 1706313700, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["whitelist"], + "action": "update", + "purpose": "Upgrade to whitelisted status for high-volume processing" + } +} +``` + ### AuthorizationRequired [TAIP-15] - Draft From b7764f73e061e0c95577e9e92d92a91d3f12fafd Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 13:02:15 +0100 Subject: [PATCH 15/32] Update CHANGELOG with TAIP-15 breaking changes (explicit connectionTypes) --- CHANGELOG.md | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f4e19..50abc2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,20 +15,26 @@ This changelog focuses on: - Breaking changes ## [Unreleased] -## [2026-01-26] - -### Added - - TAIP-20: Trusted Connections using Connect and TAIP-4 messages - - Connect message for establishing/updating trusted relationships - - Support for DDQ exchange, mutual trust, and whitelisting workflows +## [2026-01-28] ### Changed +- **BREAKING: TAIP-15 Agent Connection Protocol**: Added explicit connectionTypes field + - **NEW REQUIRED FIELD**: `connectionTypes` array now REQUIRED for all Connect messages + - Transactional connections must specify `connectionTypes: ["transaction"]` + - Added trust connection types: `ddq-access`, `mutual-trust`, `whitelist` + - Trust connections enable DDQ exchange, mutual trust establishment, and whitelisting between VASPs + - Field requirements now determined by `connectionTypes` value: + - `["transaction"]` requires: requester, principal, agents, constraints + - Trust types require: none (peer-to-peer relationships) + - **Migration**: Existing transactional Connect messages must add `connectionTypes: ["transaction"]` + - **Rationale**: Explicit type declaration follows industry standards (JSON-LD, OpenAPI, GraphQL) + - **TAIP-4**: Extended Authorize message with optional connection-specific fields - Added `approvedTypes` field for indicating approved connection types - Added `ddqDocument` field for DDQ document references - Added `trustLevel` field for trust status indicators - - These fields are only used when responding to Connect messages (TAIP-20) - + - These fields are only used when responding to trust-based Connect messages (TAIP-15) + ## [Released] ## [2025-11-25] From 6f262c723077f8f23c0c1b738c53053c68b0046e Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 13:04:17 +0100 Subject: [PATCH 16/32] Add connectionTypes to transactional connection test vectors --- test-vectors/connect/invalid-missing-constraints.json | 1 + 1 file changed, 1 insertion(+) diff --git a/test-vectors/connect/invalid-missing-constraints.json b/test-vectors/connect/invalid-missing-constraints.json index 736149b..380de5b 100644 --- a/test-vectors/connect/invalid-missing-constraints.json +++ b/test-vectors/connect/invalid-missing-constraints.json @@ -7,6 +7,7 @@ "message": { "id": "123e4567-e89b-12d3-a456-426614174001", "type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["transaction"] "from": "did:web:b2b-service.example", "to": ["did:web:vasp.example"], "created_time": 1516269022, From 9248cd28c37e0e9f34e59727e8c0a1154574d549 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 13:04:56 +0100 Subject: [PATCH 17/32] Update valid-b2b-connect.json Add connectionTypes to transactional connection test vectors --- test-vectors/connect/valid-b2b-connect.json | 1 + 1 file changed, 1 insertion(+) diff --git a/test-vectors/connect/valid-b2b-connect.json b/test-vectors/connect/valid-b2b-connect.json index d5231a7..28d9fd5 100644 --- a/test-vectors/connect/valid-b2b-connect.json +++ b/test-vectors/connect/valid-b2b-connect.json @@ -7,6 +7,7 @@ "message": { "id": "123e4567-e89b-12d3-a456-426614174000", "type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["transaction"], "from": "did:web:b2b-service.example", "to": ["did:web:vasp.example"], "created_time": 1516269022, From eab8cec0b102b8777e5d70bf473000d4841c6db4 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 13:05:15 +0100 Subject: [PATCH 18/32] Update invalid-missing-constraints.json --- test-vectors/connect/invalid-missing-constraints.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-vectors/connect/invalid-missing-constraints.json b/test-vectors/connect/invalid-missing-constraints.json index 380de5b..22ab295 100644 --- a/test-vectors/connect/invalid-missing-constraints.json +++ b/test-vectors/connect/invalid-missing-constraints.json @@ -7,7 +7,7 @@ "message": { "id": "123e4567-e89b-12d3-a456-426614174001", "type": "https://tap.rsvp/schema/1.0#Connect", - "connectionTypes": ["transaction"] + "connectionTypes": ["transaction"], "from": "did:web:b2b-service.example", "to": ["did:web:vasp.example"], "created_time": 1516269022, From ae192bf6157ad2c188467968c89d2bbfd1123e83 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 13:10:32 +0100 Subject: [PATCH 19/32] Update valid-establish-ddq.json - connectionTypes --- test-vectors/connect/valid-establish-ddq.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-vectors/connect/valid-establish-ddq.json b/test-vectors/connect/valid-establish-ddq.json index 51484e9..b657537 100644 --- a/test-vectors/connect/valid-establish-ddq.json +++ b/test-vectors/connect/valid-establish-ddq.json @@ -7,8 +7,8 @@ "body": { "@context": "https://tap.rsvp/schema/1.0", "@type": "https://tap.rsvp/schema/1.0#Connect", - "action": "establish", "connectionTypes": ["ddq-access"], + "action": "establish", "purpose": "Request DDQ access for compliance verification", "expiry": "2026-12-31T23:59:59Z" } From 5a7047459196cd66400ec711648efb26fa971c89 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 13:11:57 +0100 Subject: [PATCH 20/32] Update valid-establish-whitelist.json - connectionTypes --- test-vectors/connect/valid-establish-whitelist.json | 1 + 1 file changed, 1 insertion(+) diff --git a/test-vectors/connect/valid-establish-whitelist.json b/test-vectors/connect/valid-establish-whitelist.json index 92f78df..117f633 100644 --- a/test-vectors/connect/valid-establish-whitelist.json +++ b/test-vectors/connect/valid-establish-whitelist.json @@ -7,6 +7,7 @@ "body": { "@context": "https://tap.rsvp/schema/1.0", "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["whitelist"], "action": "establish", "connectionTypes": ["mutual-trust", "whitelist"], "purpose": "Establish mutual trust and enable straight-through processing", From 95572c264247516a422bacfdd5ab7674cbc10b6e Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 13:28:59 +0100 Subject: [PATCH 21/32] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4585b59..957b80c 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The purpose of TAIPs is to provide the community with a means to propose enhance | 15 | [Agent Connection Protocol](./TAIPs/taip-15.md) | | 16 | [Invoices](./TAIPs/taip-16.md) | | 17 | [Composable Escrow](./TAIPs/taip-17.md) | -| 20 | [Trusted Connections](./TAIPs/taip-20.md) | + ## Implementation Resources From 55b9690880b7abe96b2108c555e6073f79575328 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 17:13:21 +0100 Subject: [PATCH 22/32] Update taip-15.md - attachments to Authorize messages --- TAIPs/taip-15.md | 104 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 80 insertions(+), 24 deletions(-) diff --git a/TAIPs/taip-15.md b/TAIPs/taip-15.md index 2e6e9c8..b125066 100644 --- a/TAIPs/taip-15.md +++ b/TAIPs/taip-15.md @@ -79,7 +79,18 @@ Used when `connectionTypes` includes trust-related types (`ddq-access`, `mutual- **Note**: Trust connections SHOULD NOT include `requester`, `principal`, `agents`, or `constraints` fields. These are peer-to-peer institutional relationships. -**Attachment Usage**: Trust connections can use attachments to provide documents inline (e.g., DDQ PDFs, compliance certificates). The `ddqDocument` field in Authorize responses provides URLs for later retrieval, while attachments provide immediate document access during connection establishment. +Attachment Usage: Trust connections can use attachments to provide documents inline (e.g., DDQ PDFs, compliance certificates). The ddqDocument field in Authorize responses provides URLs for later retrieval, while attachments provide immediate document access during connection establishment. +DDQ Document Formats: Implementations MAY use any of the following formats based on their requirements: + +- application/pdf: Human-readable signed PDF documents for regulatory compliance archives +- application/json: Structured DDQ objects for automated processing and machine-readable workflows +- application/didcomm-signed+json: Cryptographically signed structured data providing both machine-readability and verifiable authenticity + +The choice of format depends on use case: + +- Use PDF for regulatory submissions requiring human-readable signed documents +- Use JSON for automated processing, field-by-field validation, and API integrations +- Use signed JSON when cryptographic verification and non-repudiation are required ## Trust Connection Types @@ -212,31 +223,14 @@ Authorize body includes additional optional fields: - `checksum` - OPTIONAL string SHA-256 hash - `expiresAt` - OPTIONAL ISO 8601 timestamp when access expires - `trustLevel` - OPTIONAL string: `whitelisted`, `trusted`, `standard`, `reviewing`, `suspended` +- `attachments` - OPTIONAL array of TAIP-2 message attachments. Can include DDQ documents or supporting materials (certificates, licenses) provided inline in the approval response -**Example Trust Connection Approval:** +**DDQ Document Delivery Options:** + +**URL-based:** Use ddqDocument.accessUrl for later retrieval (requires separate fetch) +**Inline:** Use attachments for immediate delivery (included in Authorize response) +**Both:** Can provide both URL for archival access and inline attachment for immediate use -```json -{ - "id": "auth-456", - "type": "https://tap.rsvp/schema/1.0#Authorize", - "from": "did:web:vasp-b.example", - "to": ["did:web:vasp-a.example"], - "thid": "conn-123", - "created_time": 1706227260, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Authorize", - "approvedTypes": ["ddq-access", "mutual-trust"], - "ddqDocument": { - "documentId": "ddq-uuid-789", - "version": "2024-Q4", - "accessUrl": "https://vasp-b.example/api/ddq/ddq-uuid-789", - "expiresAt": "2026-12-31T23:59:59Z" - }, - "trustLevel": "trusted" - } -} -``` #### Reject Message @@ -402,6 +396,25 @@ VASP A VASP B | | ``` + +#### Trust Connection Flow (Mutual DDQ Exchange) +``` +VASP A VASP B + | | + |--Connect---------------------------->| + | (connectionTypes: [ddq-access], | + | attachments: [VASP A's DDQ]) | + | | + |<--Authorize--------------------------| + | (approvedTypes: [ddq-access], | + | attachments: [VASP B's DDQ]) | + | | +``` +Benefits of Mutual Exchange: +- Single round-trip for both parties to exchange DDQs +- Simultaneous verification +- Reduced latency in establishing trust relationship + #### Trust Connection Update Flow ``` @@ -745,6 +758,49 @@ The following are example plaintext messages. See [TAIP-2] for how to sign the m ``` ### Authorize Connection +Example Trust Connection Approval with Inline DDQ: +```json +{ + "id": "auth-789", + "type": "https://tap.rsvp/schema/1.0#Authorize", + "from": "did:web:vasp-b.example", + "to": ["did:web:vasp-a.example"], + "thid": "conn-456", + "created_time": 1706227260, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Authorize", + "approvedTypes": ["ddq-access", "mutual-trust"], + "trustLevel": "trusted" + }, + "attachments": [ + { + "id": "ddq-response", + "description": "VASP B Due Diligence Questionnaire 2024-Q4", + "media_type": "application/json", + "data": { + "json": { + "version": "2024-Q4", + "lastUpdated": "2024-10-15T00:00:00Z", + "legalName": "VASP B Example Corp.", + "jurisdiction": "UK", + "ownershipType": "Public", + "conductsKyc": true, + "regulatoryLicenses": [ + { + "jurisdiction": "UK-FCA", + "licenseType": "Cryptoasset Registration", + "licenseNumber": "FCA-98765" + } + ], + "supportedAssets": ["BTC", "ETH", "USDC", "GBP"] + } + } + } + ] +} +``` +Example Trust Connection Approval with URL: ```json { "id": "auth-456", From 668d4c8c3542326dfb18d6206f242effe9dac079 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 17:52:44 +0100 Subject: [PATCH 23/32] Update messages.md --- messages.md | 302 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 180 insertions(+), 122 deletions(-) diff --git a/messages.md b/messages.md index 241f2fe..09f7ecc 100644 --- a/messages.md +++ b/messages.md @@ -636,6 +636,7 @@ Approves a transaction after completing compliance checks. Can also approve conn | approvedTypes | array | No | Draft ([TAIP-20]) | Array of approved connection types (for Connect responses only) | | ddqDocument | object | No | Draft ([TAIP-20]) | DDQ document reference object (for Connect responses only) | | trustLevel | string | No | Draft ([TAIP-20]) | Trust status indicator (for Connect responses only) | +| attachments | array | No | Draft ([TAIP-15]) | DIDComm attachments for inline DDQ delivery | > **Note:** The message refers to the original Transfer or Payment message via the DIDComm `thid` (thread ID) in the message envelope. When used for connections, it refers to the original Connect message. @@ -697,6 +698,52 @@ Approves a transaction after completing compliance checks. Can also approve conn } } ``` +##### Trust Connection Authorization with Inline DDQ +```json +{ + "id": "auth-trust-123", + "type": "https://tap.rsvp/schema/1.0#Authorize", + "from": "did:web:vasp-b.example", + "to": ["did:web:vasp-a.example"], + "thid": "conn-ddq-456", + "created_time": 1706227260, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Authorize", + "approvedTypes": ["ddq-access", "mutual-trust"], + "trustLevel": "trusted" + }, + "attachments": [ + { + "id": "ddq-response", + "description": "VASP B Due Diligence Questionnaire 2024-Q4", + "media_type": "application/json", + "data": { + "json": { + "version": "2024-Q4", + "lastUpdated": "2024-10-15T00:00:00Z", + "legalName": "VASP B Example Corp.", + "jurisdiction": "UK", + "ownershipType": "Public", + "conductsKyc": true, + "kycProvider": "InternalTeam", + "amlCompliance": true, + "regulatoryLicenses": [ + { + "jurisdiction": "UK-FCA", + "licenseType": "Cryptoasset Registration", + "licenseNumber": "FCA-98765" + } + ], + "supportedAssets": ["BTC", "ETH", "USDC", "GBP"], + "transactionMonitoring": true, + "sanctionsScreening": true + } + } + } + ] +} +``` ### Settle [TAIP-4] - Review @@ -1202,110 +1249,6 @@ The body object must contain: } ``` -### Connect Message Examples - -#### 1. B2B Service Connection Request -```json -{ - "id": "connect-123", - "type": "https://tap.rsvp/schema/1.0#Connect", - "from": "did:example:b2b-service", - "to": ["did:example:vasp"], - "created_time": 1516269022, - "expires_time": 1516385931, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "Connect", - "requester": { - "@id": "did:example:business-customer", - "name": "Business Customer" - }, - "principal": { - "@id": "did:example:business-customer", - "name": "Business Customer" - }, - "agents": [ - { - "@id": "did:example:b2b-service", - "name": "B2B Payment Service", - "serviceUrl": "https://b2b-service/did-comm", - "for": "did:example:business-customer" - } - ], - "constraints": { - "purposes": ["BEXP", "SUPP"], - "categoryPurposes": ["CASH", "CCRD"], - "limits": { - "per_transaction": "10000.00", - "per_day": "50000.00", - "currency": "USD" - }, - "allowedBeneficiaries": [ - { - "@id": "did:example:vendor-1", - "name": "Approved Vendor 1" - }, - { - "@id": "did:example:vendor-2", - "name": "Approved Vendor 2" - } - ], - "allowedSettlementAddresses": [ - "eip155:1:0x742d35Cc6e4dfE2eDFaD2C0b91A8b0780EDAEb58", - "eip155:1:0x89abcdefabcdefabcdefabcdefabcdefabcdef12" - ], - "allowedAssets": [ - "eip155:1/slip44:60", - "eip155:1/erc20:0xA0b86a33E6441b7178bb7094b2c4b6e5066d68B7" - ] - } - } -} -``` - -#### 2. Merchant Connection Request -```json -{ - "id": "connect-124", - "type": "https://tap.rsvp/schema/1.0#Connect", - "from": "did:web:psp.agent", - "to": ["did:web:payment.provider"], - "created_time": 1516269022, - "body": { - "@context": "https://tap.rsvp/schema/1.0", - "@type": "Connect", - "requester": { - "@id": "did:web:merchant.vasp", - "name": "Example Store" - }, - "principal": { - "@id": "did:web:merchant.vasp", - "name": "Example Store" - }, - "agents": [ - { - "@id": "did:web:psp.agent", - "name": "PSP Agent", - "for": "did:web:merchant.vasp" - } - ], - "constraints": { - "purposes": ["RCPT"], - "categoryPurposes": ["EPAY"], - "limits": { - "per_transaction": "5000.00", - "per_day": "25000.00", - "currency": "USD" - }, - "allowedAssets": [ - "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "eip155:1/erc20:0x6B175474E89094C44Da98b954EedeAC495271d0F" - ] - } - } -} -``` - ### AuthorizationRequired Message Examples #### 1. Interactive Authorization Required @@ -1457,11 +1400,10 @@ The `constraints` object defines the boundaries and permissions for transactions #### Example Connect Messages -##### Transactional Connection (B2B Payment Service) - +#### B2B Service Connection Request ```json { - "id": "123e4567-e89b-12d3-a456-426614174000", + "id": "connect-123", "type": "https://tap.rsvp/schema/1.0#Connect", "from": "did:example:b2b-service", "to": ["did:example:vasp"], @@ -1469,11 +1411,11 @@ The `constraints` object defines the boundaries and permissions for transactions "expires_time": 1516385931, "body": { "@context": "https://tap.rsvp/schema/1.0", - "@type": "https://tap.rsvp/schema/1.0#Connect", + "@type": "Connect", "connectionTypes": ["transaction"], "requester": { - "@id": "did:example:b2b-service", - "name": "B2B Payment Service" + "@id": "did:example:business-customer", + "name": "Business Customer" }, "principal": { "@id": "did:example:business-customer", @@ -1484,7 +1426,7 @@ The `constraints` object defines the boundaries and permissions for transactions "@id": "did:example:b2b-service", "name": "B2B Payment Service", "serviceUrl": "https://b2b-service/did-comm", - "for": "did:example:b2b-service" + "for": "did:example:business-customer" } ], "constraints": { @@ -1513,14 +1455,56 @@ The `constraints` object defines the boundaries and permissions for transactions "eip155:1/slip44:60", "eip155:1/erc20:0xA0b86a33E6441b7178bb7094b2c4b6e5066d68B7" ] + } + } +} +``` + +#### Merchant Connection Request +```json +{ + "id": "connect-124", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:psp.agent", + "to": ["did:web:payment.provider"], + "created_time": 1516269022, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "Connect", + "connectionTypes": ["transaction"], + "requester": { + "@id": "did:web:merchant.vasp", + "name": "Example Store" + }, + "principal": { + "@id": "did:web:merchant.vasp", + "name": "Example Store" }, - "agreement": "https://example.com/terms/v2.1" + "agents": [ + { + "@id": "did:web:psp.agent", + "name": "PSP Agent", + "for": "did:web:merchant.vasp" + } + ], + "constraints": { + "purposes": ["RCPT"], + "categoryPurposes": ["EPAY"], + "limits": { + "per_transaction": "5000.00", + "per_day": "25000.00", + "currency": "USD" + }, + "allowedAssets": [ + "eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "eip155:1/erc20:0x6B175474E89094C44Da98b954EedeAC495271d0F" + ] + } } } ``` ##### Trust Connection (DDQ Access Request) - ```json { "id": "conn-ddq-123", @@ -1533,6 +1517,7 @@ The `constraints` object defines the boundaries and permissions for transactions "@context": "https://tap.rsvp/schema/1.0", "@type": "https://tap.rsvp/schema/1.0#Connect", "connectionTypes": ["ddq-access"], + "action": "establish", "purpose": "Request DDQ access for compliance verification", "expiry": "2026-12-31T23:59:59Z" } @@ -1540,7 +1525,6 @@ The `constraints` object defines the boundaries and permissions for transactions ``` ##### Trust Connection (Mutual Trust with Whitelist) - ```json { "id": "conn-trust-456", @@ -1553,14 +1537,14 @@ The `constraints` object defines the boundaries and permissions for transactions "@context": "https://tap.rsvp/schema/1.0", "@type": "https://tap.rsvp/schema/1.0#Connect", "connectionTypes": ["mutual-trust", "whitelist"], + "action": "establish", "purpose": "Establish mutual trust and enable straight-through processing", "expiry": "2027-01-26T00:00:00Z" } } ``` -##### Trust Connection (DDQ Exchange with Inline Document) - +##### Trust Connection (DDQ Exchange with Inline Document - JSON Format) ```json { "id": "conn-ddq-789", @@ -1573,17 +1557,36 @@ The `constraints` object defines the boundaries and permissions for transactions "@context": "https://tap.rsvp/schema/1.0", "@type": "https://tap.rsvp/schema/1.0#Connect", "connectionTypes": ["ddq-access"], - "purpose": "Provide DDQ document for mutual verification", + "action": "establish", + "purpose": "Provide structured DDQ data for automated processing", "expiry": "2026-12-31T23:59:59Z" }, "attachments": [ { - "id": "ddq-doc-1", + "id": "ddq-document", "description": "VASP A Due Diligence Questionnaire 2024-Q4", - "filename": "vasp-a-ddq-2024-q4.pdf", - "media_type": "application/pdf", + "media_type": "application/json", "data": { - "base64": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlL0NhdGFsb2..." + "json": { + "version": "2024-Q4", + "lastUpdated": "2024-10-15T00:00:00Z", + "legalName": "VASP A Example Inc.", + "jurisdiction": "US", + "ownershipType": "Private", + "conductsKyc": true, + "kycProvider": "InternalTeam", + "amlCompliance": true, + "regulatoryLicenses": [ + { + "jurisdiction": "US-NY", + "licenseType": "BitLicense", + "licenseNumber": "BL-12345" + } + ], + "supportedAssets": ["BTC", "ETH", "USDC"], + "transactionMonitoring": true, + "sanctionsScreening": true + } } } ] @@ -1591,7 +1594,6 @@ The `constraints` object defines the boundaries and permissions for transactions ``` ##### Trust Connection Update (Add Whitelist) - ```json { "id": "conn-update-101", @@ -1610,6 +1612,62 @@ The `constraints` object defines the boundaries and permissions for transactions } ``` +##### DDQ Update Broadcast + +When a VASP updates their DDQ, they broadcast to all approved parties: +```json +{ + "id": "conn-update-ddq-202", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227400, + "expires_time": 1706313800, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["ddq-access"], + "action": "update", + "purpose": "Updated DDQ - Q1 2025 version with new license information" + }, + "attachments": [ + { + "id": "ddq-document-updated", + "description": "VASP A Due Diligence Questionnaire 2025-Q1 (Updated)", + "media_type": "application/json", + "data": { + "json": { + "version": "2025-Q1", + "lastUpdated": "2025-01-15T00:00:00Z", + "legalName": "VASP A Example Inc.", + "jurisdiction": "US", + "ownershipType": "Private", + "conductsKyc": true, + "kycProvider": "InternalTeam", + "amlCompliance": true, + "regulatoryLicenses": [ + { + "jurisdiction": "US-NY", + "licenseType": "BitLicense", + "licenseNumber": "BL-12345" + }, + { + "jurisdiction": "US-CA", + "licenseType": "Money Transmission License", + "licenseNumber": "MTL-67890" + } + ], + "supportedAssets": ["BTC", "ETH", "USDC", "USDT"], + "transactionMonitoring": true, + "sanctionsScreening": true, + "changeLog": "Added California MTL, expanded supported assets to include USDT" + } + } + } + ] +} +``` + ### AuthorizationRequired [TAIP-15] - Draft From 11f605129a82203825d7a8ea8a2189c21da7b0f9 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 18:01:47 +0100 Subject: [PATCH 24/32] Update taip-4.md --- TAIPs/taip-4.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/TAIPs/taip-4.md b/TAIPs/taip-4.md index fb2c6c5..d483a8e 100644 --- a/TAIPs/taip-4.md +++ b/TAIPs/taip-4.md @@ -121,9 +121,9 @@ Any agent can authorize the transaction by replying as a thread to the initial m - `amount` - OPTIONAL string with the full amount as a decimal representation of the `settlementAsset` in case it is different than the original `Payment` or `Transfer` message. - `expiry` - OPTIONAL timestamp in ISO 8601 format indicating when the authorization expires. After this time, if settlement has not occurred, the authorization should be considered invalid and settlement should not proceed. In merchant payment flows, the customer's wallet may either repeat the merchant's specified expiration time or override it with a different time. -#### Connection-Specific Fields (TAIP-20) +#### Connection-Specific Fields (TAIP-15) -When responding to `Connect` messages (see [TAIP-20]), the `Authorize` message MAY include these additional optional fields to indicate connection approval: +When responding to `Connect` messages (see [TAIP-15]), the `Authorize` message MAY include these additional optional fields to indicate connection approval: - `approvedTypes` - OPTIONAL array of strings indicating which connection types were approved from the original request (e.g., `["ddq-access", "mutual-trust"]`). This field SHOULD only be present when responding to `Connect` messages. - `ddqDocument` - OPTIONAL object containing Due Diligence Questionnaire document reference. This field SHOULD only be present when responding to `Connect` messages and granting DDQ access. Object structure: @@ -133,6 +133,7 @@ When responding to `Connect` messages (see [TAIP-20]), the `Authorize` message M - `checksum` - OPTIONAL string SHA-256 hash for integrity verification - `expiresAt` - OPTIONAL ISO 8601 timestamp when document access expires - `trustLevel` - OPTIONAL string indicating trust status between parties: `whitelisted`, `trusted`, `standard`, `reviewing`, or `suspended`. This field SHOULD only be present when responding to `Connect` messages. +- `attachments` - OPTIONAL DIDComm message attachments (e.g., DDQ documents, certificates) | These connection-specific fields SHOULD be omitted when authorizing transactions (`Transfer`, `Payment`, etc.). From 2b05000c4613c79ee5480be90f6387d5b29fa806 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 18:11:09 +0100 Subject: [PATCH 25/32] Update taip-15.md broadcast updated ddq --- TAIPs/taip-15.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/TAIPs/taip-15.md b/TAIPs/taip-15.md index b125066..f9c9fb5 100644 --- a/TAIPs/taip-15.md +++ b/TAIPs/taip-15.md @@ -443,6 +443,61 @@ Either Party Other Party | | ``` +###DDQ Update Broadcast + +When a VASP updates their DDQ, they broadcast to all ddq-access approved parties: +```json +{ + "id": "conn-update-ddq-202", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227400, + "expires_time": 1706313800, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["ddq-access"], + "action": "update", + "purpose": "Updated DDQ - Q1 2025 version with new license information" + }, + "attachments": [ + { + "id": "ddq-document-updated", + "description": "VASP A Due Diligence Questionnaire 2025-Q1 (Updated)", + "media_type": "application/json", + "data": { + "json": { + "version": "2025-Q1", + "lastUpdated": "2025-01-15T00:00:00Z", + "legalName": "VASP A Example Inc.", + "jurisdiction": "US", + "ownershipType": "Private", + "conductsKyc": true, + "kycProvider": "InternalTeam", + "amlCompliance": true, + "regulatoryLicenses": [ + { + "jurisdiction": "US-NY", + "licenseType": "BitLicense", + "licenseNumber": "BL-12345" + }, + { + "jurisdiction": "US-CA", + "licenseType": "Money Transmission License", + "licenseNumber": "MTL-67890" + } + ], + "supportedAssets": ["BTC", "ETH", "USDC", "USDT"], + "transactionMonitoring": true, + "sanctionsScreening": true, + "changeLog": "Added California MTL, expanded supported assets to include USDT" + } + } + } + ] +} +``` ### Extended Connection Flow Diagrams for Transactional connections From 54fa0444d2edb42cd421149bbc0e8e31487a0e99 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Wed, 28 Jan 2026 18:17:27 +0100 Subject: [PATCH 26/32] Update taip-15.md --- TAIPs/taip-15.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/TAIPs/taip-15.md b/TAIPs/taip-15.md index f9c9fb5..d71355d 100644 --- a/TAIPs/taip-15.md +++ b/TAIPs/taip-15.md @@ -231,6 +231,21 @@ Authorize body includes additional optional fields: **Inline:** Use attachments for immediate delivery (included in Authorize response) **Both:** Can provide both URL for archival access and inline attachment for immediate use +**Use Cases for Attachments in Authorize Response** +**Scenario 1:** Immediate DDQ Exchange +VASP A → Connect (request ddq-access) +VASP B → Authorize (approve + attach their DDQ immediately) +Benefit: One round-trip instead of two + +**Scenario 2:** Mutual DDQ Exchange +VASP A → Connect (request ddq-access + attach their DDQ) +VASP B → Authorize (approve + attach their DDQ in response) +Benefit: Simultaneous mutual exchange + +**Scenario 3:** Supporting Documents +VASP A → Connect (request whitelist) +VASP B → Authorize (approve + attach license certificates, compliance docs) +Benefit: All verification materials provided immediately #### Reject Message From cfe42b91803d4f3d89f5646c1d499d5db95e67f2 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Fri, 30 Jan 2026 13:59:33 +0100 Subject: [PATCH 27/32] Update taip-15.md added clarifications for actions in Connect messages --- TAIPs/taip-15.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/TAIPs/taip-15.md b/TAIPs/taip-15.md index d71355d..c8c1f45 100644 --- a/TAIPs/taip-15.md +++ b/TAIPs/taip-15.md @@ -74,11 +74,25 @@ A message sent to establish or update a connection between agents. Used when `connectionTypes` includes trust-related types (`ddq-access`, `mutual-trust`, `whitelist`): -- `action` - OPTIONAL string indicating connection lifecycle action: `establish` (default) or `update` +- `action` - OPTIONAL string indicating connection lifecycle action. Defaults to `establish` if not specified. Valid values: + - `establish` - Create a new connection relationship (default) + - `update` - Modify an existing connection or broadcast document updates - `attachments` - OPTIONAL array of [TAIP-2] message attachments. Can include DDQ documents or other supporting materials. When present, these documents are provided inline for review during connection establishment. **Note**: Trust connections SHOULD NOT include `requester`, `principal`, `agents`, or `constraints` fields. These are peer-to-peer institutional relationships. +#### Trust Connection Action Semantics + +The `action` field determines the purpose of the Connect message: + +- **`action="establish"`** (default): Requests to create a new trust relationship. Used for initial DDQ access requests, mutual trust establishment, or whitelist requests. + +- **`action="update"`**: Used in two scenarios: + 1. **Request connection upgrade**: Requesting additional connection types (e.g., adding `whitelist` to existing `mutual-trust`) + 2. **Broadcast document refresh**: Notifying connected parties of updated DDQ documents or supporting materials via attachments + +When `action="update"` is used with attachments containing updated documents, recipients might acknowledge receipt but are not required to send Authorize responses unless the update requests new connection types. + Attachment Usage: Trust connections can use attachments to provide documents inline (e.g., DDQ PDFs, compliance certificates). The ddqDocument field in Authorize responses provides URLs for later retrieval, while attachments provide immediate document access during connection establishment. DDQ Document Formats: Implementations MAY use any of the following formats based on their requirements: From fac04521e8ed3c11bd19b8e27e8f3590aa9b3f61 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Fri, 30 Jan 2026 14:54:28 +0100 Subject: [PATCH 28/32] Update messages.md clarified action field on Connect --- messages.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/messages.md b/messages.md index 09f7ecc..f82eeda 100644 --- a/messages.md +++ b/messages.md @@ -1364,7 +1364,7 @@ Requests a connection between agents. Supports both transactional connections (w | Attribute | Type | Required | Status | Description | |-----------|------|----------|---------|-------------| -| action | string | No | Review ([TAIP-15]) | Connection action: "establish" (default) or "update" | +| action | string | No | Review ([TAIP-15]) | Connection lifecycle action. Defaults to "establish" if not specified. Values: "establish" (create new connection), "update" (modify existing or broadcast document updates) | | attachments | array | No | Review ([TAIP-15]) | DIDComm message attachments (e.g., DDQ documents, certificates) | **Note:** Connection behavior is determined by `connectionTypes`. Transactional connections (`["transaction"]`) require `requester`, `principal`, `agents`, and `constraints`. Trust connections should omit these fields but MAY include attachments for inline document delivery. From 3f95fc0cd29855df0cf8c48bd451ab3ee27b9ccb Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Fri, 30 Jan 2026 14:59:48 +0100 Subject: [PATCH 29/32] Update valid-establish-whitelist.json fixed dupe line --- test-vectors/connect/valid-establish-whitelist.json | 1 - 1 file changed, 1 deletion(-) diff --git a/test-vectors/connect/valid-establish-whitelist.json b/test-vectors/connect/valid-establish-whitelist.json index 117f633..ee868f8 100644 --- a/test-vectors/connect/valid-establish-whitelist.json +++ b/test-vectors/connect/valid-establish-whitelist.json @@ -9,7 +9,6 @@ "@type": "https://tap.rsvp/schema/1.0#Connect", "connectionTypes": ["whitelist"], "action": "establish", - "connectionTypes": ["mutual-trust", "whitelist"], "purpose": "Establish mutual trust and enable straight-through processing", "expiry": "2027-01-26T00:00:00Z" } From d73f7d0556b26fe48b403bc7ee59b25772d4a3d5 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Fri, 30 Jan 2026 15:02:14 +0100 Subject: [PATCH 30/32] Create valid-update-ddq.json --- test-vectors/connect/valid-update-ddq.json | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 test-vectors/connect/valid-update-ddq.json diff --git a/test-vectors/connect/valid-update-ddq.json b/test-vectors/connect/valid-update-ddq.json new file mode 100644 index 0000000..a096693 --- /dev/null +++ b/test-vectors/connect/valid-update-ddq.json @@ -0,0 +1,50 @@ +{ + "id": "conn-update-ddq-456", + "type": "https://tap.rsvp/schema/1.0#Connect", + "from": "did:web:vasp-a.example", + "to": ["did:web:vasp-b.example"], + "created_time": 1706227400, + "expires_time": 1706313800, + "body": { + "@context": "https://tap.rsvp/schema/1.0", + "@type": "https://tap.rsvp/schema/1.0#Connect", + "connectionTypes": ["ddq-access"], + "action": "update", + "purpose": "Updated DDQ - Q1 2025 version with new California MTL license" + }, + "attachments": [ + { + "id": "ddq-document-updated", + "description": "VASP A Due Diligence Questionnaire 2025-Q1 (Updated)", + "media_type": "application/json", + "data": { + "json": { + "version": "2025-Q1", + "lastUpdated": "2025-01-15T00:00:00Z", + "legalName": "VASP A Example Inc.", + "jurisdiction": "US", + "ownershipType": "Private", + "conductsKyc": true, + "kycProvider": "InternalTeam", + "amlCompliance": true, + "regulatoryLicenses": [ + { + "jurisdiction": "US-NY", + "licenseType": "BitLicense", + "licenseNumber": "BL-12345" + }, + { + "jurisdiction": "US-CA", + "licenseType": "Money Transmission License", + "licenseNumber": "MTL-67890" + } + ], + "supportedAssets": ["BTC", "ETH", "USDC", "USDT"], + "transactionMonitoring": true, + "sanctionsScreening": true, + "changeLog": "Added California MTL, expanded supported assets to include USDT" + } + } + } + ] +} From 19c842c0538fe6d1b373d37e688fe635ed148d23 Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Fri, 30 Jan 2026 16:33:39 +0100 Subject: [PATCH 31/32] Update taip-15.md adding checksum for attachments --- TAIPs/taip-15.md | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/TAIPs/taip-15.md b/TAIPs/taip-15.md index c8c1f45..9e3aece 100644 --- a/TAIPs/taip-15.md +++ b/TAIPs/taip-15.md @@ -81,7 +81,7 @@ Used when `connectionTypes` includes trust-related types (`ddq-access`, `mutual- **Note**: Trust connections SHOULD NOT include `requester`, `principal`, `agents`, or `constraints` fields. These are peer-to-peer institutional relationships. -#### Trust Connection Action Semantics +##### Trust Connection Action Semantics The `action` field determines the purpose of the Connect message: @@ -93,6 +93,7 @@ The `action` field determines the purpose of the Connect message: When `action="update"` is used with attachments containing updated documents, recipients might acknowledge receipt but are not required to send Authorize responses unless the update requests new connection types. +##### Attachment usage Attachment Usage: Trust connections can use attachments to provide documents inline (e.g., DDQ PDFs, compliance certificates). The ddqDocument field in Authorize responses provides URLs for later retrieval, while attachments provide immediate document access during connection establishment. DDQ Document Formats: Implementations MAY use any of the following formats based on their requirements: @@ -106,6 +107,33 @@ The choice of format depends on use case: - Use JSON for automated processing, field-by-field validation, and API integrations - Use signed JSON when cryptographic verification and non-repudiation are required +##### Attachment Integrity Verification +When including sensitive documents or data as attachments, implementations SHOULD include integrity verification: + +- `checksum` - OPTIONAL string field within the attachment object (as a sibling to `data`) containing a SHA-256 hash for integrity verification +- Format: `sha256:` where the hash is calculated on: + - **For JSON data** (`media_type: "application/json"`): The canonical JSON string representation of the `data.json` content + - **For base64 data** (`media_type: "application/pdf"`, etc.): The raw decoded bytes of the `data.base64` content +- The checksum field MUST be placed outside the `data` object to avoid circular dependency + +```json +{ + "id": "ddq-doc-1", + "description": "VASP A DDQ 2024-Q4", + "media_type": "application/json", + "checksum": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "data": { + "json": { + "version": "2024-Q4", + "legalName": "VASP A Example Inc.", + ... + } + } +} +``` + +Recipients SHOULD verify the checksum before processing attachment content. Checksum mismatches SHOULD be treated as potential data corruption or tampering. + ## Trust Connection Types ### transaction From 3a0db6a40480fa7df2137bd82b583f9241bf6dfe Mon Sep 17 00:00:00 2001 From: martindejonge1981-collab Date: Fri, 30 Jan 2026 16:37:04 +0100 Subject: [PATCH 32/32] Update taip-4.md adding checksum --- TAIPs/taip-4.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/TAIPs/taip-4.md b/TAIPs/taip-4.md index d483a8e..742b471 100644 --- a/TAIPs/taip-4.md +++ b/TAIPs/taip-4.md @@ -137,6 +137,32 @@ When responding to `Connect` messages (see [TAIP-15]), the `Authorize` message M These connection-specific fields SHOULD be omitted when authorizing transactions (`Transfer`, `Payment`, etc.). +##### Attachment Integrity Verification + +When including sensitive documents or data as attachments (such as DDQ documents Authorize responses), implementations SHOULD include integrity verification: + +- `checksum` - OPTIONAL string field within the attachment object (as a sibling to `data`) containing a SHA-256 hash for integrity verification +- Format: `sha256:` where the hash is calculated on: + - **For JSON data** (`media_type: "application/json"`): The canonical JSON string representation of the `data.json` content + - **For base64 data** (`media_type: "application/pdf"`, etc.): The raw decoded bytes of the `data.base64` content +- The checksum field MUST be placed outside the `data` object to avoid circular dependency + +```json +{ + "id": "ddq-doc-1", + "description": "VASP A DDQ 2024-Q4", + "media_type": "application/json", + "checksum": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "data": { + "json": { + "version": "2024-Q4", + "legalName": "VASP A Example Inc.", + ... + } + } +} +``` +Recipients SHOULD verify the checksum before processing attachment content. Checksum mismatches SHOULD be treated as potential data corruption or tampering. By not providing a `settlementAddress` until after `Authorization`, beneficiary agents can reject incoming blockchain transactions for the first time.