Pular para o conteúdo

Manage the address book via the API

This guide shows you how to create and maintain counterparties and their blockchain addresses through the Ripple Custody (Wallet) API. Counterparties represent the organizations, individuals, and dApps you transact with. Addresses are the on-chain destinations that belong to them. For address book concepts, see Address book overview. To manage the address book in the console instead, see Manage address book via the console.

Address book actions

ActionConsole roleConsole procedureAPI procedure
Create a counterpartyOwner, AdministratorCreate a counterpartyCreate a counterparty
List and get counterpartiesAll except ViewerList and get counterpartiesList and get counterparties
Update a counterparty--Update a counterparty
Add an addressOwner, AdministratorAdd an addressAdd an address to a counterparty
List addressesAll except ViewerList addressesList addresses
Delete an addressOwner, AdministratorDelete a counterparty or addressGet or delete an address
Delete a counterpartyOwner, AdministratorDelete a counterparty or addressDelete a counterparty
Require approval for new addressesOwner, AdministratorRequire approval for new entries-

Permissions: In the console, owners and administrators can create and delete counterparties and addresses. Updating a counterparty is available only through the API, and you can't update an address. Owners, administrators, proposers, and approvers can approve addresses. See User roles and permissions. The API procedures need an API credential of type CONTROLS. See Prerequisites.

Prerequisites

For the base URLs, token lifetime, pagination, filtering, and error format that every endpoint shares, see API conventions.

A new address isn't usable immediately

A new address always starts with status CREATION_APPROVAL_PENDING and active: false, whether or not your organization has an Addresses approval group. Without a group, Ripple Custody (Wallet) approves the address automatically, but only after it returns the response. With a group, approvers approve the address in the console or the mobile app, and the group might require more than one approval. See Configure approval flows.

After approval, the address goes through a compliance scan (COMPLIANCE_PENDING). It becomes ENABLED with active: true only when the scan succeeds. If approvers reject the address, the approval window (the group's timeout) expires, or the scan fails, the address ends as REJECTED instead of staying pending. Get the address until it's ENABLED before you send to it.

Create a counterparty via the API

API reference: Create counterparties

Send a POST request to /v2/counterparties with a name and a details object. Set details.type to ORGANIZATION, INDIVIDUAL, or DAPP, and include the matching object:

details.typeObjectRequired fields
ORGANIZATIONorganizationlegalName (5 to 50 characters). An optional address needs address1, city, state, postCode, and country.
INDIVIDUALindividualfirstName and lastName (up to 50 characters each). An optional address needs the same fields as for an organization.
DAPPdAppNone.

Each address field must be at least 3 characters (postCode at most 20), so the API rejects a two-letter state or country code such as CA or US. Use the full name, for example California or United States. A counterparty description is optional and can be 1 to 100 characters.

If details.type doesn't match the object that you send, for example ORGANIZATION with an individual object, the request fails with PAL013.003 ("counterparty type mismatch").

curl -X POST https://api.sandbox.palisade.co/v2/counterparties \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Treasury",
    "description": "A counterparty used by the treasury department",
    "details": {
      "type": "ORGANIZATION",
      "organization": {
        "legalName": "Acme Financial Ltd",
        "address": {
          "address1": "10 Mayo Road",
          "city": "London",
          "state": "Greater London",
          "postCode": "W1 1AA",
          "country": "United Kingdom"
        }
      }
    }
  }'

The response is the new counterparty. Save the id, because you need it to add addresses.

{
  "id": "ce4918bf-a199-4ce2-85a3-d0d296855384",
  "organizationId": "a9a1de05-0b19-4fca-8597-1199353bd569",
  "createdBy": "8617b5b5-dfcf-4ffc-9f46-f7cec35a88bd",
  "createdAt": "2026-09-24T12:00:00Z",
  "updatedBy": "8617b5b5-dfcf-4ffc-9f46-f7cec35a88bd",
  "updatedAt": "2026-09-24T12:00:00Z",
  "name": "Acme Treasury",
  "description": "A counterparty used by the treasury department",
  "details": {
    "type": "ORGANIZATION",
    "organization": {
      "legalName": "Acme Financial Ltd",
      "address": {
        "address1": "10 Mayo Road",
        "city": "London",
        "state": "Greater London",
        "postCode": "W1 1AA",
        "country": "United Kingdom"
      }
    }
  },
  "addressCount": 0
}

List and get counterparties via the API

API reference: List counterparties, List counterparties with a request body, Get counterparties

List the counterparties in your organization:

curl "https://api.sandbox.palisade.co/v2/counterparties?filter.type=ORGANIZATION&pageSize=50" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
  • Paging: pageSize (default 50, maximum 1,000) and pageToken. Pass filter.nextPageToken from the response as the next pageToken. You can send pagination.pageSize and pagination.pageToken instead. If a list request on this page sends any pagination.* field, Ripple Custody (Wallet) ignores the top-level pageSize and pageToken.
  • Filters: filter.type takes ORGANIZATION, INDIVIDUAL, or DAPP. filter.id, filter.name, filter.description, filter.createdAt, and filter.updatedAt take an operator, for example filter.name.contains=acme.
  • Search: search matches the counterparty ID, name, description, and details, without regard to case.

To send the filters in a JSON body instead, use POST /v2/counterparties:list.

The response holds the counterparties in a counterparties array, each in the same shape as the create response, and a filter object with nextPageToken and total.

To get one counterparty, request it by ID:

curl https://api.sandbox.palisade.co/v2/counterparties/$COUNTERPARTY_ID \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Update a counterparty via the API

API reference: Update counterparties

Send a PUT request with the new name, which you must include, and an optional description. The PUT request replaces the stored description, so if you omit description, Ripple Custody (Wallet) clears it. On update, a description must be 5 to 100 characters. You can't change details through the API: if you include details, Ripple Custody (Wallet) ignores it.

curl -X PUT https://api.sandbox.palisade.co/v2/counterparties/$COUNTERPARTY_ID \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Treasury",
    "description": "Updated description for the treasury team"
  }'

The response is the updated counterparty.

Add an address to a counterparty via the API

API reference: Create addresses

Send a POST request to /v2/counterparties/{counterpartyId}/addresses:

FieldRequiredDescription
termsAndConditionsAcceptedYesSet to true to confirm that the ownership information you submit is correct.
details.typeYesSet to EXTERNAL.
details.externalAddress.addressYesThe on-chain address. Ripple Custody (Wallet) stores it in its canonical form, so the address in the response can differ in letter case from the one you sent: EVM addresses come back in EIP-55 checksum case, and Bech32 addresses in lowercase. For an XRP Ledger address with a destination tag, append the tag after a colon, for example rN7n7otQDd6FczFgLdSqtcsAUxDkw6fzRH:12345. The tag is 1 to 10 digits, and the r-address must pass its checksum. Enter tags without leading zeros: Ripple Custody (Wallet) treats 7 and 07 as different tags.
details.externalAddress.nameYesA name for the address, up to 50 characters.
details.externalAddress.blockchainsYesOne or more blockchains that the address supports, for example ["ETHEREUM"].
details.externalAddress.descriptionNoA description of the address, 5 to 100 characters.
custodianNoFor a custodial address, such as one held at an exchange, the custodian's name and decentralized identifier dId. If you include custodian, you must provide both, and each must be 3 to 100 characters.
curl -X POST https://api.sandbox.palisade.co/v2/counterparties/$COUNTERPARTY_ID/addresses \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "termsAndConditionsAccepted": true,
    "details": {
      "type": "EXTERNAL",
      "externalAddress": {
        "address": "0x55502b9d5a68b0F8a48384352295BeD968aD8AA4",
        "name": "Treasury",
        "description": "Wallet used to store treasury funds",
        "blockchains": ["ETHEREUM"]
      }
    }
  }'

If the address isn't valid on every blockchain in blockchains, the request fails with PAL013.015 ("address is not compatible with one or more selected blockchains").

You can't add the address of one of your organization's own wallets. If the address matches one of your wallets on any selected blockchain, the request fails with PAL013.016 ("you cannot add an internal address").

The response is the new address. If you don't send custodian, the response holds it with empty values. Its status and active fields show whether you can send to it yet:

{
  "addressId": "019d0624-b5d7-77cf-8eee-b72ceac0f71e",
  "counterpartyId": "ce4918bf-a199-4ce2-85a3-d0d296855384",
  "organizationId": "a9a1de05-0b19-4fca-8597-1199353bd569",
  "createdBy": "8617b5b5-dfcf-4ffc-9f46-f7cec35a88bd",
  "createdAt": "2026-09-24T12:05:00Z",
  "updatedBy": "8617b5b5-dfcf-4ffc-9f46-f7cec35a88bd",
  "updatedAt": "2026-09-24T12:05:00Z",
  "custodian": {
    "name": "",
    "dId": ""
  },
  "termsAndConditionsAccepted": true,
  "details": {
    "type": "EXTERNAL",
    "externalAddress": {
      "address": "0x55502b9d5a68b0F8a48384352295BeD968aD8AA4",
      "name": "Treasury",
      "description": "Wallet used to store treasury funds",
      "blockchains": ["ETHEREUM"]
    }
  },
  "status": "CREATION_APPROVAL_PENDING",
  "active": false
}

Get the address until status is ENABLED and active is true. It isn't ready to use before then. See the note under Prerequisites.

The status field takes these values:

statusactiveMeaning
CREATEDfalseRipple Custody (Wallet) stored the address and is about to request approval. This status is short-lived.
CREATION_APPROVAL_PENDINGfalseThe new address is waiting for approvers to approve it.
CREATION_APPROVAL_COMPLETEfalseRipple Custody (Wallet) recorded the approval decision. The address moves to COMPLIANCE_PENDING if approvers approved it, or to REJECTED if not. This status is short-lived.
COMPLIANCE_PENDINGfalseThe compliance scan is running.
COMPLIANCE_COMPLETEfalseThe compliance scan finished. The address moves to ENABLED if the scan succeeded, or to REJECTED if it failed. This status is short-lived.
ENABLEDtrueYou can send to the address.
REJECTEDfalseApprovers rejected the address, the approval window expired, or the scan failed.
DELETION_APPROVAL_PENDINGtrueThe deletion is waiting for approvers to approve it. The address stays active.
DELETION_APPROVAL_COMPLETEfalseRipple Custody (Wallet) recorded the deletion decision. Ripple Custody (Wallet) removes the address if approvers approve the deletion, or returns it to ENABLED if not. This status is short-lived.
DELETEDfalseYou deleted an address that was REJECTED or ERROR. The address stays in the counterparty's address list with this status.
ERRORfalseRipple Custody (Wallet) couldn't process the address. You can delete it.

List addresses via the API

API reference: List counterparty addresses, List counterparty addresses with a request body, List organization addresses, List organization addresses with a request body

To list the addresses that belong to one counterparty:

curl "https://api.sandbox.palisade.co/v2/counterparties/$COUNTERPARTY_ID/addresses?pageSize=100" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

This list returns up to 1,000 addresses for each page. The default is 50. To send the filters in a JSON body instead, use POST /v2/counterparties/{counterpartyId}/addresses:list.

To search across every counterparty, list addresses at the organization level:

curl "https://api.sandbox.palisade.co/v2/addresses?filter.blockchain.eq=ETHEREUM&filter.active.eq=true" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Both lists support these query parameters:

  • Paging: pageSize (default 50, maximum 1,000) and pageToken.
  • Filters: filter.status takes one address status, for example ENABLED. filter.addressId, filter.counterpartyId, filter.address, filter.name, filter.description, filter.active, filter.blockchain, filter.createdAt, and filter.updatedAt take an operator, for example filter.counterpartyId.eq=<id>.
  • Search: search matches the address ID, on-chain address, name, and description, without regard to case.

The organization-level list also takes an address parameter to look up an on-chain address. To send the filters in a JSON body instead, use POST /v2/addresses:list.

Both lists return an addresses array of address objects in the same shape as the create response, and a filter object with nextPageToken and total.

Get or delete an address via the API

API reference: Get addresses, Delete addresses

Get or delete an address by its counterparty ID and address ID. The address must belong to that counterparty: otherwise a get returns PAL013.012 ("address not found") and a delete returns PAL013.021. You can delete an address only when its status is ENABLED, REJECTED, or ERROR. For any other status, including CREATION_APPROVAL_PENDING, COMPLIANCE_PENDING, and DELETION_APPROVAL_PENDING, the delete fails with PAL013.021 ("the action you are attempting to perform is not allowed"). A delete request returns an empty JSON object as soon as Ripple Custody (Wallet) accepts it. If your organization has an Addresses approval group, the deletion waits for approval: the address keeps active: true with status DELETION_APPROVAL_PENDING until approvers approve it in the console. Get the address to check whether the deletion has completed. When approvers approve the deletion, Ripple Custody (Wallet) removes the address, and getting it returns PAL013.012 ("address not found"). If approvers reject the deletion or the approval window expires, the address returns to ENABLED.

If you delete an address that has status REJECTED or ERROR, Ripple Custody (Wallet) marks it DELETED but keeps it in the counterparty's address list. It still counts as one of the counterparty's addresses, you can't delete it again, and you can't delete the counterparty.

curl https://api.sandbox.palisade.co/v2/counterparties/$COUNTERPARTY_ID/addresses/$ADDRESS_ID \
  -H "Authorization: Bearer $ACCESS_TOKEN"

curl -X DELETE https://api.sandbox.palisade.co/v2/counterparties/$COUNTERPARTY_ID/addresses/$ADDRESS_ID \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Check policies before you delete

A policy rule that lists a deleted address or counterparty as the only value in a matcher no longer matches any transaction. If the matcher lists several values, the rule still matches the others. If it's the only rule for that asset, Ripple Custody (Wallet) blocks the transfers that it covered. See Policy reference.

Delete a counterparty via the API

API reference: Delete counterparties

Deleting a counterparty removes it from your address book. Delete all of the counterparty's addresses first, because you can't delete a counterparty that still has addresses. If the counterparty still has addresses, the request fails with PAL013.023 ("counterparty storage unavailable"). The message reads like a temporary outage, but retrying doesn't help: delete the addresses first. A successful delete returns an empty JSON object.

curl -X DELETE https://api.sandbox.palisade.co/v2/counterparties/$COUNTERPARTY_ID \
  -H "Authorization: Bearer $ACCESS_TOKEN"