# Solana Paymaster endpoints

All Solana Paymaster endpoints follow the JSON-RPC 2.0 specification and are available at:

```text
https://api.openfort.io/rpc/solana/{cluster}
```

Include your Openfort publishable key in the `Authorization` header:

```http
Authorization: Bearer YOUR_OPENFORT_PUBLISHABLE_KEY
```

:::info[Fee Sponsorship Policies]
By default, Solana fee sponsorship policies are applied at **project** scope: the server auto-discovers any enabled policy with a `sponsorSolTransaction` operation and validates the transaction against it (first match wins, no policy means no sponsorship).

You can optionally pass a `policyId` (`pol_<uuid>`) on any method to switch to **transaction** scope, which loads that specific policy and strictly enforces its rules. Create a fee sponsorship policy with the `sponsorSolTransaction` operation in the [Dashboard](https://dashboard.openfort.io) or via the [Policy Engine](/docs/configuration/policies).
:::

***

## signAndSendTransaction

Signs a transaction with the Openfort fee payer and immediately broadcasts it to the Solana network.

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "signAndSendTransaction",
  "params": {
    "transaction": "base64EncodedTransaction",
    "signer_key": "signerPublicKey",
    "sig_verify": true
  },
  "id": 1
}
```

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `transaction` | string | Yes | Base64-encoded transaction to sign and send |
| `signer_key` | string | No | Specific signer public key to use |
| `sig_verify` | boolean | No | Whether to verify signatures before sending |
| `policyId` | string | No | Fee sponsorship policy ID (`pol_<uuid>`) to enforce for this transaction. When provided, strictly validates the transaction against the policy's rules. When omitted, the server auto-discovers a matching project-scoped policy. |
| `externalId` | string | No | Caller-supplied identifier (1–255 chars) attached to the sponsorship record. Use it to correlate the transaction with your system and look it up later via `/v1/solana/transactions`. |

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "signature": "base58Signature",
    "signed_transaction": "base64EncodedSignedTransaction",
    "signer_pubkey": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE"
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `signature` | Transaction signature in base58 encoding |
| `signed_transaction` | The complete signed transaction in base64 format |
| `signer_pubkey` | Public key of the fee payer signer |

### Example

```typescript
const response = await fetch('https://api.openfort.io/rpc/solana/devnet', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_OPENFORT_PUBLISHABLE_KEY',
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'signAndSendTransaction',
    params: {
      transaction: base64EncodedTransaction,
      sig_verify: true
    },
    id: 1
  }),
})

const { result } = await response.json()
console.log('Transaction signature:', result.signature)
```

***

## signAndSendTransactionWithoutConfirmation

Signs a transaction with the Openfort fee payer and broadcasts it to the Solana network without waiting for confirmation. The response is returned as soon as the transaction is signed and submitted, so it is faster than `signAndSendTransaction` but the returned signature is not yet confirmed on-chain.

Use this method when you want low-latency submission and intend to track the final status yourself — either by polling the signature on a Solana RPC or by listening for the [`solana_transaction.successful` / `solana_transaction.failed` webhooks](/docs/configuration/webhooks). Openfort reconciles the on-chain status in the background and emits these events once the transaction lands or fails.

It accepts the same parameters and returns the same result shape as [`signAndSendTransaction`](/docs/products/infrastructure/paymaster/solana/endpoints#signandsendtransaction).

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "signAndSendTransactionWithoutConfirmation",
  "params": {
    "transaction": "base64EncodedTransaction",
    "signer_key": "signerPublicKey",
    "sig_verify": true
  },
  "id": 1
}
```

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `transaction` | string | Yes | Base64-encoded transaction to sign and send |
| `signer_key` | string | No | Specific signer public key to use |
| `sig_verify` | boolean | No | Whether to verify signatures before sending |
| `policyId` | string | No | Fee sponsorship policy ID (`pol_<uuid>`) to enforce for this transaction. When provided, strictly validates the transaction against the policy's rules. When omitted, the server auto-discovers a matching project-scoped policy. |
| `externalId` | string | No | Caller-supplied identifier (1–255 chars) attached to the sponsorship record. Use it to correlate the transaction with your system and look it up later via `/v1/solana/transactions`. |

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "signature": "base58Signature",
    "signed_transaction": "base64EncodedSignedTransaction",
    "signer_pubkey": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE"
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `signature` | Transaction signature in base58 encoding. The transaction has been broadcast but is **not yet confirmed** — track its final status via polling or webhooks. |
| `signed_transaction` | The complete signed transaction in base64 format |
| `signer_pubkey` | Public key of the fee payer signer |

:::info[Confirmation is asynchronous]
This method does not poll for confirmation. Openfort broadcasts the signed transaction and returns immediately. The final on-chain status is reconciled in the background and delivered through the [`solana_transaction.successful` and `solana_transaction.failed` webhooks](/docs/configuration/webhooks). A successful response means the transaction was accepted for broadcast, not that it landed on-chain.
:::

### Example

```typescript
const response = await fetch('https://api.openfort.io/rpc/solana/devnet', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_OPENFORT_PUBLISHABLE_KEY',
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'signAndSendTransactionWithoutConfirmation',
    params: {
      transaction: base64EncodedTransaction,
      sig_verify: true
    },
    id: 1
  }),
})

const { result } = await response.json()
// Returned immediately, before on-chain confirmation.
console.log('Broadcast signature:', result.signature)
```

***

## signTransaction

Signs a transaction with the Openfort fee payer without broadcasting it. The transaction must include necessary payment instructions to the fee payer.

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "signTransaction",
  "params": {
    "transaction": "base64EncodedTransaction",
    "signer_key": "signerPublicKey",
    "sig_verify": true
  },
  "id": 1
}
```

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `transaction` | string | Yes | Base64-encoded transaction with fee payment instructions |
| `signer_key` | string | No | Specific signer public key to use |
| `sig_verify` | boolean | No | Whether to verify signatures |
| `policyId` | string | No | Fee sponsorship policy ID (`pol_<uuid>`) to enforce for this transaction. When provided, strictly validates the transaction against the policy's rules. When omitted, the server auto-discovers a matching project-scoped policy. |
| `externalId` | string | No | Caller-supplied identifier (1–255 chars) attached to the sponsorship record. Use it to correlate the transaction with your system and look it up later via `/v1/solana/transactions`. |

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "signed_transaction": "base64EncodedSignedTransaction",
    "signer_pubkey": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE"
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `signed_transaction` | The complete signed transaction in base64 format |
| `signer_pubkey` | Public key of the fee payer signer |

***

## estimateTransactionFee

Estimates the transaction fee in both lamports and optionally in the specified token.

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "estimateTransactionFee",
  "params": {
    "transaction": "base64EncodedTransaction",
    "fee_token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "signer_key": "signerPublicKey",
    "sig_verify": true
  },
  "id": 1
}
```

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `transaction` | string | Yes | Base64-encoded transaction |
| `fee_token` | string | No | Token mint address for fee calculation in token units |
| `signer_key` | string | No | Specific signer public key to use for estimation |
| `sig_verify` | boolean | No | Whether to verify signatures |
| `policyId` | string | No | Fee sponsorship policy ID (`pol_<uuid>`) used to select the Kora flavor (default vs SPL). When omitted, the server auto-discovers a matching project-scoped policy. |

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "fee_in_lamports": 5000,
    "fee_in_token": 1000000,
    "signer_pubkey": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE",
    "payment_address": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE"
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `fee_in_lamports` | Transaction fee in lamports (SOL's smallest unit) |
| `fee_in_token` | Equivalent fee amount in the specified token (only present if `fee_token` was provided) |
| `signer_pubkey` | Public key of the signer used for fee estimation |
| `payment_address` | Destination address for fee payment |

***

## getSupportedTokens

Retrieves the list of tokens accepted for fee payment.

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "getSupportedTokens",
  "params": [],
  "id": 1
}
```

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tokens": [
      "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
    ]
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `tokens` | Array of token mint addresses accepted for fee payment |

***

## getConfig

Retrieves the current server configuration including enabled methods and fee payers.

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "getConfig",
  "params": [],
  "id": 1
}
```

### Parameters

`params` may be omitted, an empty array `[]`, or an object with the following optional field:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `policyId` | string | No | Fee sponsorship policy ID (`pol_<uuid>`) used to select the Kora flavor (default vs SPL) for which to return the configuration. |

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "enabled_methods": {},
    "fee_payers": [
      "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE"
    ],
    "validation_config": {}
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `enabled_methods` | Dictionary of available RPC methods and their enabled status |
| `fee_payers` | List of authorized fee payer public keys |
| `validation_config` | Server-side validation configuration |

***

## getPayerSigner

Retrieves the payer signer and payment destination addresses.

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "getPayerSigner",
  "params": [],
  "id": 1
}
```

### Parameters

`params` may be omitted, an empty array `[]`, or an object with the following optional field:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `policyId` | string | No | Fee sponsorship policy ID (`pol_<uuid>`) used to select the Kora flavor (default vs SPL) whose payer/signer should be returned. |

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "payment_address": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE",
    "signer_address": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE"
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `payment_address` | Address receiving fee payments |
| `signer_address` | Address signing transactions as fee payer |

***

## getBlockhash

Gets the latest blockhash from the Solana network.

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "getBlockhash",
  "params": [],
  "id": 1
}
```

### Parameters

`params` may be omitted, an empty array `[]`, or an object with the following optional field:

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `policyId` | string | No | Fee sponsorship policy ID (`pol_<uuid>`) used to select the Kora flavor (default vs SPL) whose Solana RPC connection should be queried. |

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "blockhash": "base58Blockhash"
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `blockhash` | Base58-encoded blockhash for transaction composition |

***

## estimateBundleFee

Estimates the aggregate fee for a [Jito bundle](/docs/products/infrastructure/paymaster/solana/jito-bundles) of 1–5 transactions, denominated in lamports and optionally in a specified SPL token. Bundles are **mainnet-only**. The estimate is for the Kora fee and **excludes the Jito tip** — when sizing the SPL reimbursement, add the tip (converted to token units) yourself. This method runs a bundle simulation on every call.

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "estimateBundleFee",
  "params": {
    "transactions": ["base64Transaction1", "base64Transaction2"],
    "fee_token": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "signer_key": "signerPublicKey"
  },
  "id": 1
}
```

`params` may also be given in array form: `[transactions]` or `[transactions, fee_token]`.

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `transactions` | string\[] | Yes | 1–5 base64-encoded transactions that make up the bundle |
| `fee_token` | string | No | Mint of the SPL token to price the fee in (must be an allowed paid token). Omit for a lamports-only estimate |
| `signer_key` | string | No | Fee payer public key used for the estimate (Openfort's `signer_address`) |
| `sig_verify` | boolean | No | Whether to verify signatures during the estimate |

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "fee_in_lamports": 15000,
    "fee_in_token": 320,
    "signer_pubkey": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE",
    "payment_address": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE"
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `fee_in_lamports` | Aggregate bundle fee in lamports (SOL), excluding the Jito tip |
| `fee_in_token` | Aggregate fee in the specified `fee_token` (present only when `fee_token` is set) |
| `signer_pubkey` | Public key of the fee payer used for the estimate |
| `payment_address` | Owner of the payment ATA the SPL reimbursement must be sent to |

***

## signAndSendBundle

Co-signs every transaction in a [Jito bundle](/docs/products/infrastructure/paymaster/solana/jito-bundles) as the fee payer and submits the bundle to Jito's block engine. Bundles execute **atomically and in order** and are **mainnet-only**. The bundle must include the Jito tip (a SOL transfer from Openfort's fee payer to a Jito tip account) and an SPL payment covering the fee and tip.

### Request

```json
{
  "jsonrpc": "2.0",
  "method": "signAndSendBundle",
  "params": {
    "transactions": ["base64Transaction1", "base64Transaction2", "base64Transaction3"],
    "signer_key": "signerPublicKey"
  },
  "id": 1
}
```

`params` may also be given in array form: `[transactions]`.

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `transactions` | string\[] | Yes | 1–5 base64-encoded transactions submitted atomically, in order |
| `signer_key` | string | No | Fee payer public key to co-sign with (Openfort's `signer_address`) |
| `sig_verify` | boolean | No | Whether to verify signatures before submitting |
| `policyId` | string | No | Fee sponsorship policy ID (`pol_<uuid>`) to enforce for this bundle. When omitted, the server auto-discovers a matching project-scoped `sponsorSolTransaction` policy |
| `externalId` | string | No | Caller-supplied identifier (1–255 chars) attached to the sponsorship record for correlation |

### Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "signed_transactions": ["base64SignedTx1", "base64SignedTx2", "base64SignedTx3"],
    "signer_pubkey": "3Z1Ef7YaxK8oUMoi6exf7wYZjZKWJJsrzJXSt1c3qrDE",
    "bundle_uuid": "0840ac6456ec76d6eb0ce077f5d61eafdc7af55eb5c5ff86d311ad84317acd44"
  }
}
```

### Response fields

| Field | Description |
|-------|-------------|
| `signed_transactions` | Base64-encoded signed transactions, one per child, in bundle order |
| `signer_pubkey` | Public key of the fee payer that co-signed |
| `bundle_uuid` | Jito bundle submission handle. Indicates the bundle was **accepted** into Jito's auction, not that it **landed** on-chain — track landing via the child signatures or the [`solana_transaction.*` webhooks](/docs/configuration/webhooks) |
