# Manage endpoints

Use this page to manage endpoint address book entries. For the concept, see [Endpoints](/pt-br/products/custody/accounts-and-assets/endpoints).

## Endpoint actions

| Action | UI procedure | API procedure | API reference |
|  --- | --- | --- | --- |
| Register an endpoint | [Register an endpoint in the UI](#register-an-endpoint-in-the-ui) | [Register an endpoint with the API](#register-an-endpoint-with-the-api) | [Propose an intent](/pt-br/products/custody/reference/api/openapi/intents/createintent), [Perform a dry run](/pt-br/products/custody/reference/api/openapi/intents/intentdryrun) |
| Register a smart contract endpoint | [Register an endpoint in the UI](#register-an-endpoint-in-the-ui) | [Register an endpoint with the API](#register-an-endpoint-with-the-api) | [Propose an intent](/pt-br/products/custody/reference/api/openapi/intents/createintent), [Perform a dry run](/pt-br/products/custody/reference/api/openapi/intents/intentdryrun) |
| View endpoint details | [View endpoints in the UI](#view-endpoints-in-the-ui) | [View endpoint details with the API](#view-endpoint-details-with-the-api) | [List endpoints](/pt-br/products/custody/reference/api/openapi/endpoints/getendpoints), [Get endpoint details](/pt-br/products/custody/reference/api/openapi/endpoints/getendpoint) |
| Update an endpoint | [Update an endpoint in the UI](#update-an-endpoint-in-the-ui) | [Update an endpoint with the API](#update-an-endpoint-with-the-api) | [Propose an intent](/pt-br/products/custody/reference/api/openapi/intents/createintent), [Perform a dry run](/pt-br/products/custody/reference/api/openapi/intents/intentdryrun) |
| Lock and unlock an endpoint | Use the API procedure. | [Lock or unlock an endpoint with the API](#lock-or-unlock-an-endpoint-with-the-api) | [Propose an intent](/pt-br/products/custody/reference/api/openapi/intents/createintent), [Perform a dry run](/pt-br/products/custody/reference/api/openapi/intents/intentdryrun) |


Endpoint changes use the standard intent flow. For signing, approval, and status checks, see [Manage intents and approvals](/pt-br/products/custody/governance/intents/manage-intents-and-approvals), [Sign intents](/pt-br/products/custody/identity-and-access/authentication/authenticate-api-requests#signing-intents-state-mutation-operations), and [Check updates](/pt-br/products/custody/governance/intents/manage-intents-and-approvals#check-state).

Use endpoint API read operations to list and get endpoint records. Use endpoint intent payloads to create, update, lock, and unlock endpoint records. Submit endpoint intents to [Propose an intent](/pt-br/products/custody/reference/api/openapi/intents/createintent). Use [Perform a dry run](/pt-br/products/custody/reference/api/openapi/intents/intentdryrun) before you sign high-risk or unfamiliar payloads.

## Common operations

| Operation | Intent type | Use when |
|  --- | --- | --- |
| Register endpoint | `v0_CreateEndpoint` | Add a ledger address or smart contract address as a known destination. |
| Update endpoint | `v0_UpdateEndpoint` | Change endpoint details such as address, trust score, ABI data, or custom properties. |
| Lock endpoint | `v0_LockEndpoint` | Disable an endpoint without deleting it. |
| Unlock endpoint | `v0_UnlockEndpoint` | Re-enable a locked endpoint. |


## Register an endpoint in the UI

You can register a ledger address or, if the ledger supports smart contracts, a smart contract address as an endpoint.

If this is a smart contract endpoint, you can provide the contract application binary interface (ABI) data when you register the endpoint.

To register an endpoint:

1. Navigate to **Endpoints**.
2. Select **Create an endpoint**.
3. Enter the details of the endpoint, such as the name and description.
4. Select the ledger.
5. Enter the endpoint address.
6. If the endpoint address is a smart contract address, enter smart contract ABI details in one of the following ways:
  - Enter the ABI in JSON format.
  - Upload the ABI in a file.
7. Enter the trust score as a number from `0` to `100`.
8. To allow this endpoint to share its address, ledger, and tag with an existing endpoint, turn off **Prevent duplicate endpoints**. The toggle is on by default, so the UI rejects a duplicate unless you turn it off.
9. Select **Submit for Approval** and [sign the operation with the app](/pt-br/products/custody/identity-and-access/authentication/ui-authentication#sign-ui-operations).


The new endpoint is registered when the intent is successfully executed.

## Register an endpoint with the API

You can register a ledger address or, if the ledger supports smart contracts, a smart contract address as an endpoint.

If this is a smart contract endpoint, you can provide the contract application binary interface (ABI) data when you create the endpoint.

Before you register an endpoint, prepare:

| Prerequisite | Additional information |
|  --- | --- |
| Ledger ID | [List ledgers](/pt-br/products/custody/reference/api/openapi/ledgers/getledgers) |
| Endpoint address | For a custody account address, [retrieve the account address](/pt-br/products/custody/reference/api/openapi/accounts/getaccountaddress). For an external address or smart contract address, collect the address before submission. Ripple Custody (Vault) validates the address against the selected ledger's format and rejects an invalid address. |
| New IDs | Prepare an endpoint ID and an intent ID in standard UUID format. |


Create an endpoint by submitting a `v0_CreateEndpoint` intent.

Duplicate endpoint prevention is optional
By default, Ripple Custody (Vault) accepts an endpoint that duplicates the address, ledger, and destination tag or memo of an existing endpoint in the domain. To reject duplicates, set `allowDuplicate` to `false` in the payload. See [Duplicate endpoint prevention](#duplicate-endpoint-prevention).

Address validation
On EVM ledgers, Solana, Stellar, Tron, and XRPL, Ripple Custody (Vault) validates the address against the ledger's format when you create or update an endpoint, and rejects an address that isn't valid for that ledger. Endpoints on other ledgers are accepted without address validation. A rejection is refused at submission with an HTTP 400 response and `reason: "InvalidEndpointAddressError"`; the message echoes the submitted address and the expected ledger format. A dry run reports the same failure in the `errors` array — for example, `"The provided address (...) does not match the expected format for a <ledger> address."` — before you submit. This error is distinct from the duplicate-endpoint error, so integrations can handle it programmatically. For the address formats accepted per ledger, see [Supported blockchain ledgers](/pt-br/products/custody/reference/supported-ledgers#address-formats-by-ledger).

### Duplicate endpoint prevention

The optional `allowDuplicate` field controls whether Ripple Custody (Vault) accepts an endpoint that matches an existing endpoint in the domain on address, ledger, and destination tag or memo. It applies to `v0_CreateEndpoint` and `v0_UpdateEndpoint` payloads.

- **Omitted:** Ripple Custody (Vault) accepts the duplicate. This is the default.
- **`true`:** Ripple Custody (Vault) accepts the duplicate.
- **`false`:** Ripple Custody (Vault) rejects the intent with `An endpoint with the same address, ledger and tag already exists: <id> on this domain`, and a dry run reports the conflict.


When you set `allowDuplicate` to `false`, an empty destination tag counts as a value: only one endpoint without a tag can exist for a given domain, address, and ledger. To reuse an address with prevention on, register each endpoint with a distinct destination tag or memo, or use the existing endpoint.

On an update, Ripple Custody (Vault) runs the check only when the update changes the address or the tag. Setting `allowDuplicate` on its own doesn't change the endpoint.

Deprecated field
Ripple introduces `allowDuplicate` as a deprecated field and plans to remove it on October 1, 2027. After that date, Ripple Custody (Vault) rejects every duplicate endpoint, as it did in versions 1.40 and 1.41. If your integration relies on creating several endpoints for one address, plan the migration before then. Omitting the field never bypasses address validation or any other endpoint check.

### Ledger address endpoint payload

The SDK examples assume a configured client. See [Integrate via SDK](/pt-br/products/custody/get-started/integrate-via-sdk). Each SDK `create` method builds the `v0_CreateEndpoint` payload, signs the intent, and submits it in one call. The following examples register a ledger address endpoint:

API
```json
{
  "payload": {
    "id": "c3ddaca1-07d8-437d-803b-bfdef7833aa4",
    "address": "0x258aE861829FB6B33e7528308cA2938638590F34",
    "trustScore": 50,
    "ledgerId": "ethereum-testnet",
    "alias": "Ethereum Testnet",
    "lock": "Unlocked",
    "description": "Ethereum testnet wallet",
    "customProperties": {},
    "allowDuplicate": false,
    "type": "v0_CreateEndpoint"
  }
}
```

TypeScript
```typescript
const pending = await client.endpoints.create(
  'Ethereum Testnet',
  '0x258aE861829FB6B33e7528308cA2938638590F34',
  50,
  'ethereum-testnet',
  {
    id: 'c3ddaca1-07d8-437d-803b-bfdef7833aa4',
    description: 'Ethereum testnet wallet',
  },
);
await pending.waitAccepted(60_000);
await pending.waitExecuted(120_000);
```

Java
```java
PendingIntent pending = client.endpoints().create(
    domainId,
    UUID.fromString("c3ddaca1-07d8-437d-803b-bfdef7833aa4"),
    "Ethereum Testnet",
    "0x258aE861829FB6B33e7528308cA2938638590F34",
    50,
    "ethereum-testnet",
    null, // no ABI for a ledger address
    Map.of());
pending.waitAccepted(60);
pending.waitExecuted(120);
```

The Java `create` method doesn't take a description.

Python
```python
from uuid import UUID

pending = client.endpoints.create(
    "Ethereum Testnet",
    address="0x258aE861829FB6B33e7528308cA2938638590F34",
    trust_score=50,
    ledger_id="ethereum-testnet",
    id=UUID("c3ddaca1-07d8-437d-803b-bfdef7833aa4"),
    description="Ethereum testnet wallet",
)
pending.wait_accepted(timeout=60)
pending.wait_executed(timeout=120)
```

### Smart contract endpoint payload

API
```json
{
  "payload": {
    "id": "b445e1d1-41fe-468a-a600-1b9ad7b057e1",
    "address": "0xb2f701a94d864b131fd47c9cf4563e6298afdbfc",
    "trustScore": 50,
    "ledgerId": "ethereum-testnet",
    "parameters": {
      "ABI": "<ABI_JSON_STRING>",
      "type": "Ethereum"
    },
    "alias": "MTT Smart Contract",
    "lock": "Unlocked",
    "description": "MTT token contract",
    "customProperties": {},
    "type": "v0_CreateEndpoint"
  }
}
```

TypeScript
```typescript
// contractAbi is the parsed ABI array. The SDK serializes it into parameters.ABI.
const pending = await client.endpoints.create(
  'MTT Smart Contract',
  '0xb2f701a94d864b131fd47c9cf4563e6298afdbfc',
  50,
  'ethereum-testnet',
  {
    id: 'b445e1d1-41fe-468a-a600-1b9ad7b057e1',
    abi: contractAbi,
    description: 'MTT token contract',
  },
);
await pending.waitAccepted(60_000);
await pending.waitExecuted(120_000);
```

Java
```java
import com.ripple.custody.models.CoreEndpointLedgerParametersEthereum;

CoreEndpointLedgerParametersEthereum abiParameters = new CoreEndpointLedgerParametersEthereum()
    .type(CoreEndpointLedgerParametersEthereum.TypeEnum.ETHEREUM)
    .ABI(abiJson); // the ABI as a JSON string

PendingIntent pending = client.endpoints().create(
    domainId,
    UUID.fromString("b445e1d1-41fe-468a-a600-1b9ad7b057e1"),
    "MTT Smart Contract",
    "0xb2f701a94d864b131fd47c9cf4563e6298afdbfc",
    50,
    "ethereum-testnet",
    abiParameters,
    Map.of());
pending.waitAccepted(60);
pending.waitExecuted(120);
```

Python
```python
from uuid import UUID

# abi_json is the ABI as a JSON string.
pending = client.endpoints.create(
    "MTT Smart Contract",
    address="0xb2f701a94d864b131fd47c9cf4563e6298afdbfc",
    trust_score=50,
    ledger_id="ethereum-testnet",
    id=UUID("b445e1d1-41fe-468a-a600-1b9ad7b057e1"),
    abi=abi_json,
    description="MTT token contract",
)
pending.wait_accepted(timeout=60)
pending.wait_executed(timeout=120)
```

Fields of the `payload` block to note are:

| Field | Description |
|  --- | --- |
| `type` | `v0_CreateEndpoint` |
| `id` | New endpoint ID in UUID format. |
| `address` | Ledger address or smart contract address. |
| `trustScore` | Score from `0` to `100` that policies can use to define destination-specific workflows. |
| `ledgerId` | Ledger that scopes the address. |
| `parameters` | Ledger-specific parameters. The `type` field selects the format. For smart contract endpoints, set `type` to `Ethereum` and `ABI` to the ABI string in JSON format. For destination tags and memos on XRPL, Stellar, and Hedera, see [Destination tag and memo payloads](#destination-tag-and-memo-payloads). |
| `alias` | Human-readable endpoint name. |
| `lock` | Initial lock state. Use `Unlocked` to make the endpoint available after approval. |
| `description` | Optional endpoint description. |
| `customProperties` | Required key-value metadata object with string values. Use `{}` when empty. |
| `allowDuplicate` | Optional. Set to `false` to reject an endpoint that duplicates an existing endpoint's address, ledger, and tag. Omit it or set it to `true` to accept duplicates. Deprecated: Ripple plans to remove it on October 1, 2027. See [Duplicate endpoint prevention](#duplicate-endpoint-prevention). |


Dry run before submitting:

```sh
curl -X POST "${CUSTODY_API_URL}/v1/intents/dry-run" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d @create-endpoint-intent.json
```

Submit the signed intent:

```sh
curl -X POST "${CUSTODY_API_URL}/v1/intents" \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  -H "Content-Type: application/json" \
  -d @signed-create-endpoint-intent.json
```

The endpoint is registered when the endpoint creation intent is successfully approved and executed.

### Destination tag and memo payloads

On ledgers that route funds at a shared address by tag, store the tag on the endpoint in the `parameters` field. The endpoint is then the source of truth: transfers that use the endpoint as their destination carry its tag automatically.

| Ledger | `parameters` field | Format |
|  --- | --- | --- |
| XRPL | `destinationTag` | Integer, 0 to 4294967295 (32-bit unsigned). |
| Stellar | `memo` | One typed object: `Text` (1-28 bytes), `Id` (unsigned 64-bit integer as a string), `Hash` or `Return` (64-character hex). |
| Hedera | `memo` | UTF-8 string, 1 to 100 bytes. |


Ripple Custody (Vault) validates the value against the target ledger's format when you create or update the endpoint and rejects invalid values.

An XRPL endpoint with a destination tag:

```json
{
  "payload": {
    "id": "8f4f4be6-1f4e-4a2b-9b6d-1d1b6f0f2a10",
    "address": "rEXAMPLEaBcDeFgHiJkLmNoPqRsTuVwXyZ",
    "trustScore": 50,
    "ledgerId": "xrpl-testnet",
    "parameters": {
      "destinationTag": 745692,
      "type": "XRPL"
    },
    "alias": "Exchange deposit account",
    "lock": "Unlocked",
    "description": "Exchange omnibus address, customer tag 745692",
    "customProperties": {},
    "type": "v0_CreateEndpoint"
  }
}
```

A Stellar endpoint uses a typed memo object instead, for example `"memo": { "value": "745692", "type": "Id" }`; a Hedera endpoint uses a plain string, `"memo": "customer-745692"`.

The SDK endpoint methods accept only Ethereum ABI parameters, so they can't set a destination tag or memo. Register these endpoints with the API. To set a tag or memo on a single transfer instead, use the chain-specific SDK methods described in [Send assets with the API](/pt-br/products/custody/transactions/send-and-receive/send-assets-api).

## View endpoints in the UI

To view endpoints in the UI:

1. Navigate to **Endpoints**.
2. Review the endpoint list.
3. Open an endpoint to review its details.


The endpoint list shows known destinations in the selected domain.

## View endpoint details with the API

To view endpoint details:

1. If you do not know the endpoint ID, retrieve a list of endpoints in the domain with [List endpoints](/pt-br/products/custody/reference/api/openapi/endpoints/getendpoints). You can filter the list by ledger with the `ledgerId` query parameter.
2. Retrieve endpoint details with [Get endpoint details](/pt-br/products/custody/reference/api/openapi/endpoints/getendpoint), using the endpoint ID from step 1.


The following examples list endpoints and get one endpoint's details:

API
```http
GET /v1/domains/{domainId}/endpoints/{endpointId}
Authorization: Bearer <your_jwt_token>
```

TypeScript
```typescript
import type { CoreTrustedEndpointsCollection } from '@ripple/ripple-custody-client-lib-typescript';

const page = (await client.endpoints.list({ limit: 50 })) as CoreTrustedEndpointsCollection;
for (const item of page.items) {
  console.log(item.data.id, item.data.alias, item.data.address);
}

// get() returns the endpoint's data object.
const endpoint = await client.endpoints.get(endpointId);
console.log(endpoint.lock, endpoint.trustScore, endpoint.metadata.revision);
```

Java
```java
import com.ripple.custody.models.CoreEndpoint;
import com.ripple.custody.models.CoreTrustedEndpoint;
import com.ripple.custody.models.CoreTrustedEndpointsCollection;

CoreTrustedEndpointsCollection page = client.endpoints().list(domainId, 50, null);
for (CoreTrustedEndpoint item : page.getItems()) {
  System.out.println(item.getData().getId() + " " + item.getData().getAlias());
}

CoreEndpoint endpoint = client.endpoints().get(domainId, endpointId).getData();
System.out.println(endpoint.getLock() + " " + endpoint.getTrustScore());
```

Python
```python
page = client.endpoints.list(limit=50, ledger_id=["ethereum-testnet"])
for item in page.items:
    print(item.data.id, item.data.alias, item.data.address)

# get() returns the endpoint's data object.
endpoint = client.endpoints.get(endpoint_id)
print(endpoint.lock, endpoint.trust_score, endpoint.metadata.revision)
```

The TypeScript and Python `list` methods return one page by default. Pass `autoPaginate: true` (TypeScript) or `auto_paginate=True` (Python) to collect every page into one list. In Java, use `client.endpoints().stream(domainId)`. Only the Python `list` method accepts the query filters in the following table, as keyword arguments such as `ledger_id`.

Use `List endpoints` query parameters to narrow or sort endpoint lists:

| Task | Query parameter |
|  --- | --- |
| Filter by ledger | `ledgerId` |
| Filter by alias | `alias` |
| Filter by address | `address` |
| Filter by description | `metadata.description` |
| Filter by creator | `metadata.createdBy` |
| Filter by last modifier | `metadata.lastModifiedBy` |
| Filter by lock state | `lock` |
| Filter by custom properties | `metadata.customProperties` |
| Paginate results | `limit`, `startingAfter` |
| Sort results | `sortBy`, `sortOrder` |


The API returns trusted endpoint objects. Inspect the `data` object for endpoint details.

Depending on the endpoint type, `data` includes:

- Endpoints that are ledger addresses do not include ABI data in the `parameters` field.
- Endpoints that are associated with a smart contract address have ABI data in the `parameters` field in JSON format.


The `data` object also includes `domainId`, `metadata`, `lock`, and `trustScore` so you can confirm ownership, revision, availability, and policy inputs before you use the endpoint in a transaction order. The trusted endpoint envelope also includes `signature` and `signingKey`.

## Update an endpoint in the UI

You can update the following details of an endpoint:

- Name and description.
- Address.
- Trust score.
- Custom properties.


You cannot update the ledger.

To update an endpoint:

1. Navigate to **Endpoints**.
2. At the end of the endpoint row, open the contextual menu and select **Edit**.
3. Update the details of the endpoint.
4. If you change the address or tag, decide whether to keep **Prevent duplicate endpoints** on. Turn it off to let the endpoint share its address, ledger, and tag with an existing endpoint.
5. Select **Submit for Approval** and [sign the operation with the app](/pt-br/products/custody/identity-and-access/authentication/ui-authentication#sign-ui-operations).


The endpoint details are updated when the intent is successfully executed.
Ripple Custody (Vault) increases the endpoint revision.

## Update an endpoint with the API

You can update general details of an endpoint such as the address and the trust score. For a smart contract endpoint, you can also update the application binary interface (ABI) data. Ripple Custody (Vault) validates the address against the endpoint's ledger and rejects an update that would set an invalid address.

Endpoint updates use a `v0_UpdateEndpoint` intent. Submit the update through the standard intent flow, then check the endpoint after execution.

Do not include `ledgerId` in endpoint update payloads. The API specification marks `ledgerId` as deprecated for `v0_UpdateEndpoint`, and you cannot update the ledger in the UI.

Omit `parameters` unless you update ABI data for a smart contract endpoint or a destination tag/memo (see [Update a destination tag or memo](#update-a-destination-tag-or-memo)). Include `allowDuplicate: false` to reject an update that would make the endpoint a duplicate of an existing one. See [Duplicate endpoint prevention](#duplicate-endpoint-prevention).

The following examples update an endpoint:

API
```json
{
  "payload": {
    "reference": {
      "id": "c3ddaca1-07d8-437d-803b-bfdef7833aa4",
      "revision": 2
    },
    "address": "0x258aE861829FB6B33e7528308cA2938638590F34",
    "trustScore": 75,
    "alias": "Ethereum treasury endpoint",
    "description": "Updated Ethereum treasury destination",
    "customProperties": {},
    "type": "v0_UpdateEndpoint"
  }
}
```

TypeScript
```typescript
const current = await client.endpoints.get(endpointId);

// Pass the current address, ledger, and parameters to change only the other fields.
const pending = await client.endpoints.update(
  endpointId,
  'Ethereum treasury endpoint',
  current.address,
  75,
  {
    ledgerId: current.ledgerId,
    parameters: current.parameters,
    description: 'Updated Ethereum treasury destination',
  },
);
await pending.waitAccepted(60_000);
await pending.waitExecuted(120_000);
```

Java
```java
CoreEndpoint current = client.endpoints().get(domainId, endpointId).getData();

// Pass the current address, ledger, and parameters to change only the other fields.
// A null revision makes the SDK use the endpoint's current revision.
PendingIntent pending = client.endpoints().update(
    domainId,
    endpointId,
    null,
    "Ethereum treasury endpoint",
    current.getAddress(),
    75,
    current.getLedgerId(),
    current.getParameters(),
    "Updated Ethereum treasury destination",
    Map.of());
pending.waitAccepted(60);
pending.waitExecuted(120);
```

Python
```python
current = client.endpoints.get(endpoint_id)

# Pass the current address, ledger, and parameters to change only the other fields.
pending = client.endpoints.update(
    endpoint_id,
    "Ethereum treasury endpoint",
    address=current.address,
    trust_score=75,
    ledger_id=current.ledger_id,
    parameters=current.parameters,
    description="Updated Ethereum treasury destination",
)
pending.wait_accepted(timeout=60)
pending.wait_executed(timeout=120)
```

For a smart contract endpoint, include the `parameters` object with the updated ABI data:

```json
{
  "parameters": {
    "ABI": "<ABI_JSON_STRING>",
    "type": "Ethereum"
  }
}
```

With an SDK, pass the updated ABI as `abi` (TypeScript and Python) or as a `CoreEndpointLedgerParametersEthereum` object (Java) instead of the current parameters. Because this changes `parameters`, the [SDK endpoint immutability check](#sdk-endpoint-immutability-check) applies.

The SDK `update` methods replace the endpoint's mutable fields with the values you pass. They don't fill omitted fields from the current endpoint. Unlike the earlier API guidance, they send `ledgerId` in the payload, so pass the endpoint's current value. If you don't pass the current revision, the SDK reads it from the endpoint.

### SDK endpoint immutability check

Before an SDK submits an endpoint update, it reads the endpoint and compares the `address`, `ledgerId`, and `parameters` values you pass with the current ones. A change to any of them redefines a trusted counterparty, so create a new endpoint instead where possible. If you omit `ledgerId` or `parameters` and the endpoint has a value for that field, the SDK counts it as a change.

- **Default:** The SDK raises an error and doesn't submit the update.
- **To allow the change:** Set `RC_ENFORCE_IMMUTABLE_ENDPOINTS=false`, or set `rc_enforce_immutable_endpoints = false` in the configuration file. The SDK then logs a warning and submits the update. In Java, the warning goes to the `com.ripple.custody.namespaces.Endpoints` logger, which is off by default. For more information, see [SDK configuration](/pt-br/products/custody/developer-experience/sdks/configuration).


This client-side check is separate from the server-side [duplicate endpoint prevention](#duplicate-endpoint-prevention).

### Update a destination tag or memo

The `v0_UpdateEndpoint` payload accepts the same `parameters` field as creation, so you can add, change, or clear an endpoint's destination tag or memo. Ripple Custody (Vault) validates the update against the same per-ledger format rules. When the payload sets `allowDuplicate` to `false`, it also rejects an update that would collide with an existing endpoint on domain, address, ledger, and destination tag, and a dry run reports the conflict before you submit.

The SDK endpoint models describe only Ethereum ABI parameters, so use the API to update an endpoint that has a destination tag or memo.

## Lock or unlock an endpoint with the API

Endpoint lock-state changes use the standard intent flow.

| Update | Intent type | Additional information |
|  --- | --- | --- |
| Lock an endpoint | `v0_LockEndpoint` | [Submit an intent](/pt-br/products/custody/governance/intents/manage-intents-and-approvals#submit-an-intent-with-the-api) |
| Unlock an endpoint | `v0_UnlockEndpoint` | [Submit an intent](/pt-br/products/custody/governance/intents/manage-intents-and-approvals#submit-an-intent-with-the-api) |


Submit a lock intent with the current endpoint reference:

API
```json
{
  "payload": {
    "reference": {
      "id": "c3ddaca1-07d8-437d-803b-bfdef7833aa4",
      "revision": 2
    },
    "type": "v0_LockEndpoint"
  }
}
```

TypeScript
```typescript
// Omit revision to let the SDK read the current revision.
const pending = await client.endpoints.lock(endpointId);
await pending.waitAccepted(60_000);
await pending.waitExecuted(120_000);

// To re-enable the endpoint later:
// await client.endpoints.unlock(endpointId);
```

Java
```java
// A null revision makes the SDK read the current revision.
PendingIntent pending = client.endpoints().lock(domainId, endpointId, null);
pending.waitAccepted(60);
pending.waitExecuted(120);

// To re-enable the endpoint later:
// client.endpoints().unlock(domainId, endpointId, null);
```

Python
```python
# Omit revision to let the SDK read the current revision.
pending = client.endpoints.lock(endpoint_id)
pending.wait_accepted(timeout=60)
pending.wait_executed(timeout=120)

# To re-enable the endpoint later:
# client.endpoints.unlock(endpoint_id)
```

Use `v0_UnlockEndpoint` with the same reference shape to re-enable the endpoint.

## Operational checklist

Before submitting an endpoint intent:

- Confirm the endpoint is in the correct domain.
- Confirm the ledger and address are correct.
- Confirm the trust score matches your policy model.
- Confirm whether the endpoint represents a smart contract and needs ABI data.
- Dry run the payload when using the API.
- Verify the executed change by viewing the endpoint.