> For the complete documentation index, see [llms.txt](https://docs.diversifi.trade/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.diversifi.trade/diversifi-for-partners/integration-guide/platform-integration.md).

# Platform integration

### 15. Platform Integration Overview

The platform integration API (`/v1/integrations/`) is designed for third-party platforms that want to embed DiversiFi deposits and withdrawals for their own end users without requiring each user to authenticate directly with DiversiFi.

**Key difference from Sections 8–13:** The standard `/v1/positions/` endpoints act on behalf of the authenticated wallet. The `/v1/integrations/` endpoints let your platform specify any `user_wallet` address, so a single API key can serve many users.

#### How it works

1. Your platform holds one API key with the `integrations` permission.
2. When a user wants to deposit or withdraw, your backend calls the relevant `/v1/integrations/` endpoint, passing the user's wallet address as `user_wallet`. The response includes an unsigned transaction and a `confirmToken`.
3. Your frontend presents the transaction to the user for signing (e.g., via their wallet adapter — Phantom, Backpack, etc.).
4. The user signs and submits the transaction to the Solana network.
5. Your backend calls `POST /v1/integrations/confirm` with the transaction signature and the `confirmToken` — this links the on-chain transaction to your API key and returns the `transactionGroupId`.
6. Your platform polls the transaction status using the `transactionGroupId` returned by the confirm call.

#### Authentication

API key with `integrations` permission, sent as a Bearer token:

```
Authorization: Bearer dfi_your_api_key_here
```

**Rate limit:** 60 requests per minute (independent of the standard 120 req/min limit).

> Contact the DiversiFi team to request an API key with `integrations` permission.

***

### 16. Platform Deposit Flow

#### Get the unsigned deposit transaction

```shellscript
GET /v1/integrations/deposit/tx
```

| Parameter        | Type   | Required | Description                                           |
| ---------------- | ------ | -------- | ----------------------------------------------------- |
| `basket_address` | string | Yes      | The basket address / Index PDA (base58)               |
| `amount`         | number | Yes      | USDC amount to deposit (human-readable, e.g. `100.5`) |
| `user_wallet`    | string | Yes      | The end user's Solana wallet address (base58)         |

**Response:**

```typescript
{
  "success": true,
  "data": {
    "unsignedTxs": ["<base64-encoded transaction>"],
    "confirmToken": "<one-time token, valid 30 minutes>"
  }
}
```

Store the `confirmToken` — you will need it in the next step.

**Error responses:**

| `message`                                     | Cause                               |
| --------------------------------------------- | ----------------------------------- |
| `"Invalid basket_address"`                    | Malformed address                   |
| `"Invalid user_wallet"`                       | Malformed address                   |
| `"Basket not found"`                          | Unknown or inactive basket          |
| `"Basket operations are currently paused"`    | Basket temporarily disabled         |
| `"Minimum deposit for this basket is X USDC"` | Amount below the per-basket minimum |

#### Sign and submit

Decode the base64 transaction, present it to the user for signing via their wallet, then submit it to the Solana network:

```typescript
const tx = VersionedTransaction.deserialize(Buffer.from(unsignedTxs[0], 'base64'));
tx.sign([userKeypair]); // or wallet adapter
const signature = await connection.sendRawTransaction(tx.serialize());
await connection.confirmTransaction(signature, 'confirmed');
```

#### Confirm

After the transaction is on-chain, call:

```shellscript
POST /v1/integrations/confirm
Content-Type: application/json

{
  "signature": "<base58 transaction signature>",
  "confirmToken": "<token from the deposit/tx response>"
}
```

**Response:**

```typescript
{
  "success": true,
  "data": {
    "transactionGroupId": "a3f8c2d1e5b4f097"
  }
}
```

The `transactionGroupId` is a 16-character hex ID you use to poll status (Section 18). It is also deterministic — computed as `sha256(signature).slice(0, 16)` — so you can derive it locally, but the confirm response is the canonical source.

> **Why is the confirm step required?** It links the on-chain transaction to your API key so that only your key can retrieve it via `/transaction/:id`. Without it, the transaction processes normally but will not be visible through the integrations API.

***

### 17. Platform Withdrawal Flow

#### Get the unsigned withdrawal transaction

```shellscript
GET /v1/integrations/withdraw/tx
```

| Parameter        | Type   | Required | Description                                   |
| ---------------- | ------ | -------- | --------------------------------------------- |
| `basket_address` | string | Yes      | The basket address / Index PDA (base58)       |
| `amount`         | number | Yes      | LP token amount to withdraw (human-readable)  |
| `user_wallet`    | string | Yes      | The end user's Solana wallet address (base58) |

**Response:** Same shape as the deposit response — `unsignedTxs` array and a `confirmToken`.

The user signs and submits the transaction. Then call `POST /v1/integrations/confirm` with the signature and `confirmToken`, exactly as in Section 15. The confirm response returns the `transactionGroupId` for polling.

***

### 18. Platform Refund Flow

If a deposit or withdrawal is stuck — for example, if a swap failed and tokens are locked in the user's on-chain escrow account — the platform can initiate a refund on behalf of the user.

#### Check refund eligibility

```shellscript
GET /v1/integrations/refund/check
```

| Parameter        | Type   | Required |
| ---------------- | ------ | -------- |
| `basket_address` | string | Yes      |
| `user_wallet`    | string | Yes      |

**Response:**

```typescript
{
  "success": true,
  "data": {
    "canRefund": true,
    "refundType": "deposit",
    "deposit": {
      "hasBalance": true,
      "balance": 100.5,
      "canRefund": true
    },
    "withdrawal": {
      "hasBalance": false,
      "balance": 0,
      "canRefund": false
    }
  }
}
```

`refundType` is `"deposit"`, `"withdraw"`, or `null`. Use this value directly as the `refund_type` parameter in the next call.

#### Get the unsigned refund transaction

```
GET /v1/integrations/refund/tx
```

| Parameter        | Type   | Required | Description                 |
| ---------------- | ------ | -------- | --------------------------- |
| `basket_address` | string | Yes      |                             |
| `user_wallet`    | string | Yes      |                             |
| `refund_type`    | string | Yes      | `"deposit"` or `"withdraw"` |

**Response:**

```typescript
{
  "success": true,
  "data": {
    "unsignedTx": "<base64-encoded transaction>",
    "transactionType": "deposit"
  }
}
```

Note: unlike the deposit/withdrawal endpoints, `unsignedTx` here is a single string, not an array.

The user signs and submits the refund transaction. No confirm step is required for refunds — the `transactionGroupId` can be derived locally as `sha256(signature).slice(0, 16)`.

***

### 19. Tracking Transaction Status

```shellscript
GET /v1/integrations/transaction/:transactionGroupId
```

Use the `transactionGroupId` returned by `POST /confirm` (Sections 15–16) or derived locally from a refund signature (Section 17) to poll status. You can only look up transactions that were confirmed with your own API key.

**States:**

| `state`               | Meaning                                                                     |
| --------------------- | --------------------------------------------------------------------------- |
| `initialized`         | On-chain escrow confirmed. Queued for execution.                            |
| `executing`           | Jupiter swaps are in progress.                                              |
| `completed`           | All swaps finished. dTokens minted (deposit) or USDC returned (withdrawal). |
| `partially_completed` | Some swaps succeeded, some failed. A partial refund may be available.       |
| `refunded`            | The transaction was cancelled and tokens returned to the user.              |
| `failed`              | Terminal failure.                                                           |

**Response (200):**

```typescript
{
  "success": true,
  "data": {
    "transactionGroupId": "a3f8c2d1e5b4f097",
    "transactionType": "deposit",
    "state": "completed",
    "walletAddress": "<user wallet>",
    "basketAddress": "<basket address>",
    "initializeSignature": "<on-chain signature of the initialize tx>",
    "totalAmount": "100500000",
    "usedAmount": "100500000",
    "remainingAmount": "0",
    "totalTokenAmount": "0",
    "totalUsdcAmount": "100500000",
    "lpTokenPriceSnapshot": "1050000",
    "finalIndexTokenBalance": "95714285",
    "hasRefund": false,
    "refundTransactionId": null,
    "refundedAmount": null,
    "refundSignature": null,
    "depositPDA": "<deposit escrow address>",
    "withdrawalPDA": null,
    "swaps": [
      {
        "signature": "...",
        "tokenInMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
        "amountIn": "50250000",
        "tokenOutMint": "So11111111111111111111111111111111111111112",
        "amountOut": "187543210",
        "confirmedAt": "2025-03-24T12:34:58.000Z",
        "slot": 312847562,
        "lpTokensMinted": "47857142"
      }
    ],
    "failedSwaps": [],
    "initializedAt": "2025-03-24T12:34:56.789Z",
    "executedAt": "2025-03-24T12:35:01.123Z",
    "completedAt": "2025-03-24T12:35:04.456Z",
    "refundedAt": null
  }
}
```

**Note:** All token amounts are in atomic units (smallest denomination). Divide by `10^decimals` to get human-readable values. USDC uses 6 decimals; dToken decimals can be read from the mint account (byte offset 44, as shown in Section 4).

**Error responses:**

| Status | Cause                                                             |
| ------ | ----------------------------------------------------------------- |
| `404`  | Transaction not found, or it was initiated by a different API key |
| `401`  | Missing or invalid API key                                        |

***

### 20. Example TypeScript Implementation

See [`platform_integration_example.ts`](https://docs.diversifi.trade/~/revisions/ZF6Hb4ijE6lwNA3OwEft/diversifi-for-partners/integration-guide/platform-integration/platform_integration_example.ts) for a complete working example covering all four operations: deposit, withdrawal, refund, and status polling.

```shellscript
npx tsx platform_integration_example.ts
```

**.env required:**

```dotenv
# DiversiFi API
DIVERSIFI_API_KEY=dfi_your_api_key_here
API_BASE_URL=https://dev-api.diversifi.trade

# Solana RPC (used by both examples)
RPC_URL=https://api.mainnet-beta.solana.com

# deposit_withdraw_example.ts — demo keypair (JSON array of 64 bytes)
# In production, users sign client-side via wallet adapter — never expose secret keys
USER_SECRET_KEY=

# price_derivation.ts — optional Jupiter API key for higher rate limits
JUP_API_KEY=
```

view .env file on github : <https://github.com/SolutioFi-io/diversifi-integration-guide/blob/main/.env.example>
