Ripple Custody (Vault) provides client SDKs that wrap the REST API. This quickstart takes you from installing an SDK to submitting your first intent. Use it when you're starting a new integration in TypeScript, Java, or Python.
Each SDK handles authentication, intent signing and submission, response-signature verification, and pagination. Your code calls typed methods instead of sending raw HTTP requests.
| SDK | Package | Runtime |
|---|---|---|
| TypeScript | @ripple/ripple-custody-client-lib-typescript | Node.js 22.19 or later. Promise-based API. |
| Java | com.ripple.custody.platform.contrib:ripple-custody-client-lib-java | Java 17 or later. Synchronous API. |
| Python | ripple_custody_client_lib_python | Python 3.9 or later. Synchronous and asynchronous clients. |
For a feature comparison and the full reference, see Client SDKs.
The SDKs are pre-1.0. Their APIs may change between releases. Pin the exact version that you test with.
Before you start, you must have:
- Access to a running Ripple Custody (Vault) instance, including its API base URL and the URL of its OpenID Connect (OIDC) issuer.
- A registered user with a P-256 signing key pair. You keep the private key in a PEM file, and the platform holds the public key. To create and register the key pair, see Generate a key pair and register a public key.
- The user ID and domain ID of that registered user.
- The notary API public key for your environment. By default, the SDKs verify the signature on API responses, and they require this key to do so. Get the key from your Ripple Custody (Vault) administrator.
Ripple provides the SDK packages as files. To get the package for your language, contact the Ripple support team. Then install the SDK from the file.
File names include the SDK version. In the following commands, replace {version} with the version that you received.
Install the package from the .tgz file:
npm install ./ripple-ripple-custody-client-lib-typescript-{version}.tgznpm records the dependency in package.json as a file: path. Keep the .tgz file where your build can reach it, for example in your repository.
To sign with AWS Key Management Service (KMS) or Azure Key Vault instead of a local key file, also install the provider SDK. The TypeScript SDK loads it on demand:
npm install @aws-sdk/client-kms # AWS KMS
npm install @azure/keyvault-keys @azure/identity # Azure Key VaultThe TypeScript and Python packages install a ripple-custody command. The Java SDK has no command-line helper.
| Command | TypeScript | Python |
|---|---|---|
ripple-custody quickstart | Prints the getting-started steps. | Creates a project directory with a config.toml, a new signing key, and a runnable script. |
ripple-custody keygen | Generates a signing key pair. Choose the curve with --curve (P-256, secp256k1, or Ed25519) and write the private key to a file with --out. | Generates a signing key pair. Choose the key type with --key-type (Secp256r1, Secp256k1, or Ed25519) and write the private key to a file with --out. |
ripple-custody config init | Copies the configuration template to ./config.toml, or to the path you pass. | Writes an annotated config.toml, plus .envrc and .gitignore stubs, to the current directory. |
ripple-custody doctor | Checks your configuration and connectivity to the cluster. | Checks your installation, configuration, and connectivity. Add --json for output you can attach to a support request. |
Both keygen commands print the public key in base64-encoded DER (SPKI) format. The platform expects this format when you register a key.
If you installed the TypeScript SDK locally, run the command through npx, for example npx ripple-custody doctor.
All three SDKs read a config.toml file and RC_* environment variables. An environment variable always overrides the matching value in the file. By default, each SDK looks for config.toml at the path in RC_CONFIG_FILE, then in the current working directory, then at ~/.config/ripple-custody/config.toml.
All three SDKs use the same key names, so the same file works in each language. Create a config.toml file like the following, and replace the placeholders with your instance's URLs, your IDs, and the notary API public key:
api_base_url = "https://<api-host>"
oidc_issuer_url = "https://<auth-host>/realms/<realm>"
private_key_file = "/path/to/signing-key.pem"
rc_user_id = "<your-user-id>"
rc_domain_id = "<your-domain-id>"
notary_api_public_key = "<notary-api-public-key>"Don't set client_id when you sign with a private key. The SDKs treat client_id as half of a client-credentials pair, and the TypeScript and Python SDKs fail unless you also supply a client secret. All three SDKs reject keys in config.toml that they don't recognize.
If you know the exact token endpoint, set token_endpoint in place of oidc_issuer_url.
To configure the SDK from the environment only, set the matching environment variables instead. The variable names are the same in all three SDKs:
export RC_API_BASE_URL="https://<api-host>"
export RC_OIDC_ISSUER_URL="https://<auth-host>/realms/<realm>"
export RC_PRIVATE_KEY_FILE="/path/to/signing-key.pem"
export RC_USER_ID="<your-user-id>"
export RC_DOMAIN_ID="<your-domain-id>"
export RC_NOTARY_API_PUBLIC_KEY="<notary-api-public-key>"In the preceding examples, config.toml holds no secrets, so you can keep it in version control. Keep secrets out of the file:
- Private key. The SDK reads the key from the file path in
private_key_fileorRC_PRIVATE_KEY_FILE. The key itself never appears in the configuration. Restrict the key file's permissions so that only your application's user can read it. Bothkeygencommands write the file with mode0600. For production, sign with a KMS instead of a local file. For more information, see Authentication and signing. - Client secret. If you use the client-credentials grant, set the secret in the
RC_CLIENT_SECRETenvironment variable. The Python SDK reads the secret only fromRC_CLIENT_SECRET. The TypeScript SDK acceptsclient_secretinconfig.tomlbut logs a warning when you set it there. The Java SDK rejectsclient_secretin the file. Don't commit a file that holds the secret.
For every setting, including TLS and mutual TLS settings, see Configure the SDK.
Load the configuration and create a client. If the configuration is incomplete, this step fails immediately instead of on the first API call. For example, it fails if response verification is on and you haven't set a notary API public key.
The following code loads config.toml from the default location and creates a client:
import {
CustodyClient,
loadConfiguration,
} from '@ripple/ripple-custody-client-lib-typescript';
const client = new CustodyClient(loadConfiguration());To load a file from another location, pass its path: loadConfiguration('/etc/custody/config.toml').
The SDK obtains and refreshes OAuth access tokens for you.
List the domains that your user can see. A successful call confirms that authentication and response verification both work:
const page = await client.governance.domains.list({ limit: 5 });
const domains = Array.isArray(page) ? page : page.items;
for (const domain of domains) {
console.log(`${domain.data.id}: ${domain.data.alias}`);
}list() returns one page by default. Pass autoPaginate: true to get every item as a flat array instead.
For a complete program, see example 00 (getting started). To get the examples, see Examples.
You make changes in Ripple Custody (Vault) by submitting signed intents. The SDK builds the intent, signs it with your key, submits it, and returns a pending intent that you can wait on.
The following example proposes a new user with the viewer role. Your user must have permission to create users in the domain. The new user generates their own key pair and gives you only the public key, in base64-encoded DER format. Replace <new-user-public-key> with that key:
const pending = await client.governance.users.create(
'new-user@example.com',
'<new-user-public-key>',
['viewer'],
{ loginIds: [{ id: 'new-user@example.com', providerId: 'harmonize' }] },
);
await pending.waitAccepted(30_000); // timeout in milliseconds
await pending.waitExecuted(120_000);
console.log(`Intent ${pending.intentId} executed`);The two waits track the two stages of an intent:
- Wait accepted returns when the platform accepts the request and creates the intent.
- Wait executed waits for a final intent state. An intent can execute after it collects the approvals its policy requires, or end in
Failed,Rejected, orExpired. In TypeScript, the wait fails unless the intent executed. In Java and Python, it returns the intent in whatever final state it reaches, so check the status before reporting success or starting a dependent operation. In all SDKs, the wait fails if the timeout expires.
For a complete program, see example 10 (create user). To get the examples, see Examples.
For approvals, rejections, and transaction intents, see Work with intents.
When you're done, close the client to release its network connections:
await client.close();- Client SDKs: compare SDK features by language.
- Examples: get runnable example programs for common tasks.
- Agent skills: help an AI coding assistant write code with the SDK.
- Configure the SDK: every configuration key and environment variable.
- Authentication and signing: client credentials, key types, and KMS-backed signers.
- HashiCorp Vault: sign with a Vault Transit key.
- Work with intents: wait, approve, and reject intents.
- Response verification: how the SDKs verify API responses.
- Errors and HTTP behavior: exception types, timeouts, and retries.
- Migrate from the legacy Java SDK: move from the
com.metacoSDK.