> For the complete documentation index, see [llms.txt](https://docs.tylt.money/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tylt.money/tylt-embedded-wallet-service/transactions/travel-rule-counterparty.md).

# Travel Rule Counterparty

### Add Counterparty Information

Submits originator or beneficiary counterparty information associated with a crypto transaction.

This endpoint should be used where Travel Rule information is required before an on-chain payout can be processed.

### Endpoint

```http
POST /whitelabel/compliance/travelRule/addCounterparty
```

### Request Headers

```http
x-tlp-apikey: <api-key>
x-tlp-signature: <hmac-signature>
Content-Type: application/json
```

### Authorization Requirements

The request requires:

* An approved and active end user
* Replay protection
* Email OTP
* Authenticator TOTP
* A valid HMAC signature
* A whitelisted IP address

### Request Fields

Provide at least one of the following user identifiers: `endUserEmail`, `endUserId`, or `externalUserId`.

| Field            | Type   |    Required | Description                        |
| ---------------- | ------ | ----------: | ---------------------------------- |
| `endUserId`      | Number | Conditional | Tylt's end user Id                 |
| `endUserEmail`   | String | Conditional | End users registered email         |
| `externalUserId` | String | Conditional | Merchant’s own user identifier     |
| `timestamp`      | Number |         Yes | Current epoch time in milliseconds |
| `nonce`          | String |         Yes | Unique request identifier          |
| `emailCode`      | String |         Yes | Email OTP                          |
| `googleAuthCode` | String |         Yes | End user’s Authenticator code      |

The request must also contain the counterparty and transaction information required by Tylt’s Travel Rule API.

This may include:

* Transaction ID
* Counterparty type
* Counterparty name
* Counterparty wallet address
* Counterparty institution or VASP
* Country
* Originator or beneficiary information
* Self-hosted-wallet declaration
* Supporting Travel Rule information

### Example Request Structure

```json
{
  "endUserId": 20001, // Optional: Provide one user identifier only
  "endUserEmail": "joe@example.com", // Optional: Alternative to endUserId and externalUserId
  "externalUserId": "user-10021", // Optional: Alternative to endUserId and endUserEmail
  "transactionId": "98765",
  "counterparty": {
    "firstName": "Acme",
    "lastName": "Private Limited",
    "type": "company"
  },
  "emailCode": "123456",
  "googleAuthCode": "654321",
  "timestamp": 1700000000000,
  "nonce": "f67d664b-f60c-472a-9433-505f8450bb87"
}
```

The exact `counterparty` structure must follow the Travel Rule schema supplied by Tylt.

### Code Snippet

{% tabs %}
{% tab title="JavaScript (Axios)" %}

```javascript
import crypto from 'crypto';
import axios from 'axios';

const apiKey = 'your-api-key';
const apiSecret = 'your-api-secret';

const requestBody = {
    endUserId: 20001, // Optional: Provide one user identifier only
    endUserEmail: "joe@example.com", // Optional: Alternative to endUserId and externalUserId
    externalUserId: "user-10021", // Optional: Alternative to endUserId and endUserEmail
    transactionId: '2144884',
    counterparty: {
        firstName: 'Joe',
        lastName: 'Doe',
        type: 'individual'
    },
    emailCode: '538940',
    googleAuthCode: '915461',
    timestamp: Date.now(),
    nonce: crypto.randomBytes(8).toString('hex')
};

const raw = JSON.stringify(requestBody);
const signature = crypto.createHmac('sha256', apiSecret).update(raw).digest('hex');

const headers = {
    'x-tlp-apikey': apiKey,
    'x-tlp-signature': signature,
    'Content-Type': 'application/json'
};

axios.post('https://api.tylt.money/whitelabel/compliance/travelRule/addCounterparty', raw, { headers })
    .then(response => console.log(response.data))
    .catch(error => console.error('Error:', error.response ? error.response.data : error.message));
```

{% endtab %}
{% endtabs %}

### Example Response

```json
{
  "success": true,
  "msg": "Counterparty added successfully."
}
```

> The final response structure depends on the deployed Travel Rule controller.

### Transaction Ownership

Tylt validates that the referenced transaction belongs to the identified end user.

A merchant cannot submit or retrieve Travel Rule information for a transaction belonging to:

* Another user under the same merchant
* A user under another merchant
* An unrelated Tylt account

### Possible Errors

| HTTP Status | Message                                            | Description                                                   |
| ----------- | -------------------------------------------------- | ------------------------------------------------------------- |
| `400`       | Validation error                                   | Required Travel Rule information is missing or invalid        |
| `400`       | `Parameter emailCode is mandatory.`                | Email OTP was not supplied                                    |
| `400`       | `Parameter googleAuthCode is mandatory.`           | Authenticator code was not supplied                           |
| `400`       | `Access Denied! OTP does not match!`               | Email OTP is incorrect or expired                             |
| `400`       | `Unable to verify 2FA. Contact Support.`           | TOTP verification failed                                      |
| `401`       | `Api Key authentication failed!`                   | API authentication failed                                     |
| `403`       | `IP not whitelisted.`                              | Request originated from an unauthorized IP                    |
| `403`       | `End user is suspended.`                           | The end user is suspended                                     |
| `403`       | KYC approval required                              | End-user KYC is not approved                                  |
| `404`       | `End user not found for this owner.`               | No matching user was found                                    |
| `404`       | Transaction not found                              | The transaction does not exist or does not belong to the user |
| `409`       | `Duplicate request detected (nonce already used).` | The nonce was previously used                                 |
| `503`       | `Unable to verify IP whitelist.`                   | Tylt could not verify the IP whitelist                        |

***

## Recommended Internal Transfer Flow

A standard internal transfer should follow this sequence:

1. Confirm that the sender’s `walletOpsAllowed` status is `true`.
2. Confirm that the recipient belongs to the same merchant.
3. Retrieve the sender’s available balance.
4. Collect the amount and asset.
5. Request the sender’s transaction OTP.
6. Collect the email OTP and Authenticator code.
7. Generate the timestamp and nonce.
8. Sign and submit the internal-transfer request.
9. Display the transfer result to the sender.
10. Update the wallet balances and transaction history shown to both users.
