{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Connect to a Custodian","siteUrl":"https://opensource.ripple.com/","meta":[{"name":"google-site-verification","content":"bLwyBi1imklcIuQxZ7JeI_kRF5Mg7yfr6arpEQV2nsE"}],"llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]},"description":"This tutorial demonstrates how to connect to a custodian (Palisade and Ripple Custody)."},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"connect-to-a-custodian","__idx":0},"children":["Connect to a Custodian"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This tutorial demonstrates how to connect to a custodian (Palisade and Ripple Custody)."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"ts","header":{"controls":{"copy":{}}},"source":"/**\n * Custodian-specific connections.\n *\n * Each connector is constructed and authenticated independently, then passed to\n * `SimpleXRPL.init`. Once bound, every vertical operation works the same regardless\n * of which connector owns the acting account — the SDK routes each write to the\n * custodian that holds the account.\n *\n * Config is read from the environment / your secrets manager so this drops\n * straight into your app — never hard-code credentials or keys. Endpoints below\n * point at the sandbox / testnet; swap them for production when you go live.\n */\nimport {\n  LocalSigner,\n  PalisadeCustody,\n  RippleCustody,\n  SimpleXRPL,\n} from 'simplexrpl'\n\n// --- Palisade (Wallet-as-a-Service) ---------------------------------------\n\n// Palisade authenticates via OAuth client credentials and acts on a specific\n// vault/wallet. `create` exchanges credentials and discovers the org's wallets.\nconst palisade = await PalisadeCustody.create({\n  baseUrl: 'https://api.sandbox.palisade.co', // sandbox (TESTNET data)\n  // Palisade scopes one permission set per credential, so a full setup needs\n  // two: a wallet-read credential (account discovery) and a transactions one.\n  credentials: {\n    wallets: {\n      clientId: process.env.PALISADE_WALLETS_CLIENT_ID ?? '',\n      clientSecret: process.env.PALISADE_WALLETS_CLIENT_SECRET ?? '',\n    },\n    transactions: {\n      clientId: process.env.PALISADE_TX_CLIENT_ID ?? '',\n      clientSecret: process.env.PALISADE_TX_CLIENT_SECRET ?? '',\n    },\n  },\n  primary: {\n    vaultId: process.env.PALISADE_VAULT_ID ?? '',\n    walletId: process.env.PALISADE_WALLET_ID ?? '',\n  },\n  // Enable the raw sign-only fallback for transactors Palisade has no native\n  // operation for. Off by default.\n  allowRawSigning: false,\n})\n\n// --- Ripple Custody -------------------------------------------------------\n\n// Ripple Custody authenticates with an intent-author key (PEM contents or a\n// path to a `.pem`) exchanged for a token, and operates within one Custody\n// domain. Unlike Palisade — which has one shared, public sandbox URL — a\n// Custody deployment is per-tenant: its gateway/token URLs point at the\n// instance Ripple provisions for you (sandbox or production), so they belong\n// in config rather than hard-coded. `fromEnv` reads every `RIPPLE_CUSTODY_*`\n// variable for exactly this reason:\nconst rippleCustody = await RippleCustody.fromEnv({\n  primary: process.env.RIPPLE_CUSTODY_PRIMARY_ADDRESS ?? '',\n})\n\n// The explicit form, if you configure it yourself rather than via the env:\n// const rippleCustody = await RippleCustody.create({\n//   gatewayUrl: process.env.RIPPLE_CUSTODY_GATEWAY_URL ?? '',\n//   auth: {\n//     signingKey: process.env.RIPPLE_CUSTODY_AUTH_SIGNING_KEY ?? '',\n//     tokenUrl: process.env.RIPPLE_CUSTODY_AUTH_TOKEN_URL ?? '',\n//   },\n//   domainId: process.env.RIPPLE_CUSTODY_DOMAIN_ID ?? '',\n//   primary: process.env.RIPPLE_CUSTODY_PRIMARY_ADDRESS ?? '',\n// })\n\n// --- Local signing (self-custody; keys held in-process) -------------------\n// For self-custodied accounts. `fromEnv` scans the environment for seeds.\nconst local = LocalSigner.fromEnv()\n\n// --- Bind the connectors --------------------------------------------------\n\nconst client = await SimpleXRPL.init({\n  xrpldUrl: 'wss://s.altnet.rippletest.net:51233', // XRPL Testnet\n  signers: [palisade, rippleCustody, local],\n  // The default backend for operations called without an explicit `from`.\n  primarySigner: rippleCustody,\n})\n\nconsole.log('connected with', client.signers.length, 'connectors')\nawait client.disconnect()\n","lang":"ts"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"see-also","__idx":1},"children":["See Also"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/simplexrpl/references/connectors"},"children":["Connectors"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/simplexrpl/references/connectors/palisade"},"children":["Palisade connector"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/simplexrpl/references/connectors/ripple-custody"},"children":["Ripple Custody connector"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/simplexrpl/references/connectors/local"},"children":["Local connector"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/simplexrpl/references/client#simplexrplinit"},"children":["SimpleXRPL.init()"]}]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/docs/simplexrpl/references/connectors/connector-routing"},"children":["Connector Routing"]}]}]}]},"headings":[{"value":"Connect to a Custodian","id":"connect-to-a-custodian","depth":1},{"value":"See Also","id":"see-also","depth":2}],"frontmatter":{"seo":{"description":"This tutorial demonstrates how to connect to a custodian (Palisade and Ripple Custody).","title":"Connect to a Custodian"},"labels":["simpleXRPL","SDK"]},"editPage":{"to":"https://github.com/ripple/opensource.ripple.com/tree/main/docs/simpleXRPL/tutorials/connect-to-custodian.md"},"lastModified":"2026-08-26T05:15:32.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/docs/simplexrpl/tutorials/connect-to-custodian","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}