> ## Documentation Index
> Fetch the complete documentation index at: https://developers.jup.ag/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Borrow with Privy

> Create a position, deposit collateral, and borrow assets using Privy embedded wallets.

Create a borrow position, deposit collateral, and borrow assets from Jupiter Lend vaults using Privy embedded wallets. The full flow uses two transactions: one to create a position and deposit collateral, and one to borrow.

## Prerequisites

```bash theme={null}
npm install @solana/web3.js@1 bn.js @jup-ag/lend @privy-io/node
```

***

## Create Position and Deposit Collateral

**Step 1**

### Import Dependencies

```typescript theme={null}
import { PrivyClient } from "@privy-io/node";
import {
  Connection,
  PublicKey,
  TransactionMessage,
  VersionedTransaction,
} from "@solana/web3.js";
import BN from "bn.js";
import { getOperateIx } from "@jup-ag/lend/borrow";
```

**Step 2**

### Configure Privy and Initialise Client

Set up your Privy credentials, Solana connection, and borrow parameters.

```typescript theme={null}
const PRIVY_APP_ID = "put-your-privy-app-id-here";
const PRIVY_APP_SECRET = "put-your-privy-app-secret-here";
const RPC_ENDPOINT = "https://api.mainnet-beta.solana.com";
const VAULT_ID = 1; // target vault (market) ID
const COLLATERAL_AMOUNT = new BN(1_000_000); // e.g. 1 USDC (6 decimals)
const AUTH_KEY_ID = "put-your-auth-key-id-here"; // from Privy dashboard or REST API
const AUTH_KEY_PRIVATE = "put-your-auth-key-private-here"; // P-256 private key
const WALLET_ID = "put-your-wallet-id-here";

const privy = new PrivyClient({
  appId: PRIVY_APP_ID,
  appSecret: PRIVY_APP_SECRET,
});

const connection = new Connection(RPC_ENDPOINT);
```

> [!NOTE]
>
> `AUTH_KEY_ID` identifies the authorization key (from dashboard/API), `AUTH_KEY_PRIVATE` is the P-256 private key used for signing. See the [Privy authorization keys docs](https://docs.privy.io/controls/authorization-keys/owners/overview) for setup.

**Step 3**

### Get Wallet Address

```typescript theme={null}
const wallet = await privy.wallets().get(WALLET_ID);
if (!wallet) {
  throw new Error(`Wallet ${WALLET_ID} not found`);
}
const signer = new PublicKey(wallet.address);
```

**Step 4**

### Build Create Position + Deposit Instructions

Pass `positionId: 0` to create a new position and deposit collateral in a single transaction. The SDK returns `nftId` for future operations.

```typescript theme={null}
const { ixs, addressLookupTableAccounts, nftId } = await getOperateIx({
  vaultId: VAULT_ID,
  positionId: 0, // 0 = create new position + deposit in one tx
  colAmount: COLLATERAL_AMOUNT,
  debtAmount: new BN(0),
  connection,
  signer,
});

console.log("New position ID (nftId):", nftId);

if (!ixs?.length) {
  throw new Error("No deposit instructions returned by Jupiter Lend SDK");
}
```

Save `nftId` for subsequent operations (borrow, repay, withdraw). With `positionId: 0`, the SDK batches position creation and collateral deposit into one transaction.

**Step 5**

### Build and Sign Transaction

Borrow transactions use versioned (v0) format with address lookup tables.

```typescript theme={null}
const { blockhash, lastValidBlockHeight } =
  await connection.getLatestBlockhash();

const message = new TransactionMessage({
  payerKey: signer,
  recentBlockhash: blockhash,
  instructions: ixs,
}).compileToV0Message(addressLookupTableAccounts ?? []);

const transaction = new VersionedTransaction(message);
const serializedTx = Buffer.from(transaction.serialize()).toString("base64");

const signResponse = await privy
  .wallets()
  .solana()
  .signTransaction(WALLET_ID, {
    transaction: serializedTx,
    authorization_context: {
      authorization_private_keys: [AUTH_KEY_PRIVATE],
    },
  });

if (!signResponse?.signed_transaction) {
  throw new Error("Privy signing failed: no signed transaction returned");
}
```

**Step 6**

### Send Transaction

```typescript theme={null}
const signedTxBytes = Buffer.from(
  signResponse.signed_transaction as string,
  "base64"
);
const signature = await connection.sendRawTransaction(signedTxBytes, {
  skipPreflight: false,
});
await connection.confirmTransaction(
  { signature, blockhash, lastValidBlockHeight },
  "confirmed"
);
console.log("Position created and collateral deposited! Signature:", signature);
```

***

## Borrow Against Collateral

Once you have a position with deposited collateral, borrow assets against it.

**Step 1**

### Build Borrow Instructions

Use the `nftId` from the previous step as `positionId`. Set `colAmount` to 0 and `debtAmount` to the borrow amount.

```typescript theme={null}
const BORROW_AMOUNT = new BN(100_000); // e.g. 0.1 USDT (6 decimals)
const POSITION_ID = nftId; // from create position step above

const { ixs: borrowIxs, addressLookupTableAccounts: borrowAlts } =
  await getOperateIx({
    vaultId: VAULT_ID,
    positionId: POSITION_ID,
    colAmount: new BN(0),
    debtAmount: BORROW_AMOUNT,
    connection,
    signer,
  });

if (!borrowIxs?.length) {
  throw new Error("No borrow instructions returned by Jupiter Lend SDK");
}
```

> [!WARNING]
>
> Your borrow capacity depends on collateral value and the vault's LTV limits. Monitor your position to avoid liquidation.

**Step 2**

### Build, Sign, and Send

```typescript theme={null}
const borrowBlockhash = await connection.getLatestBlockhash();

const borrowMessage = new TransactionMessage({
  payerKey: signer,
  recentBlockhash: borrowBlockhash.blockhash,
  instructions: borrowIxs,
}).compileToV0Message(borrowAlts ?? []);

const borrowTx = new VersionedTransaction(borrowMessage);
const borrowSerialised = Buffer.from(borrowTx.serialize()).toString("base64");

const borrowSignResponse = await privy
  .wallets()
  .solana()
  .signTransaction(WALLET_ID, {
    transaction: borrowSerialised,
    authorization_context: {
      authorization_private_keys: [AUTH_KEY_PRIVATE],
    },
  });

if (!borrowSignResponse?.signed_transaction) {
  throw new Error("Privy signing failed: no signed transaction returned");
}

const borrowSignedBytes = Buffer.from(
  borrowSignResponse.signed_transaction as string,
  "base64"
);
const borrowSig = await connection.sendRawTransaction(borrowSignedBytes, {
  skipPreflight: false,
});
await connection.confirmTransaction(
  {
    signature: borrowSig,
    blockhash: borrowBlockhash.blockhash,
    lastValidBlockHeight: borrowBlockhash.lastValidBlockHeight,
  },
  "confirmed"
);
console.log("Borrow successful! Signature:", borrowSig);
```

The borrowed tokens are now in the Privy wallet. Repay with the standard [Repay](https://developers.jup.ag/docs/lend/borrow/repay.md) flow using the same `positionId`.

***

## Operate Parameters

`getOperateIx` accepts the following parameters:

| Parameter | Type | Description |
| - | - | - |
| `vaultId` | `number` | Target vault (market) ID. |
| `positionId` | `number` | Position NFT ID. Use `0` to create a new position and deposit in one transaction. |
| `colAmount` | `BN` | Signed collateral amount in base units. **Positive** = deposit. **Negative** = withdraw. Use `new BN(0)` for borrow/repay-only. |
| `debtAmount` | `BN` | Signed debt amount in base units. **Positive** = borrow. **Negative** = repay. Use `new BN(0)` for deposit/withdraw-only. |
| `connection` | `Connection` | Solana RPC connection. |
| `signer` | `PublicKey` | Wallet that signs the transaction (position owner). |

***

## Related

> [card] [Earn with Privy](https://developers.jup.ag/docs/lend/wallets/privy-earn.md)
>
> Deposit and withdraw with Privy wallets

> [card] [Deposit Collateral](https://developers.jup.ag/docs/lend/borrow/deposit.md)
>
> Standard collateral deposit with keypair signing


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.