> 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>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.diversifi.trade/diversifi-for-partners/integration-guide/platform-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
