PAPI
SDK

Direct Mode

Direct exchange access without the PAPI API proxy

Direct Mode

In direct mode, the SDK connects directly to exchange APIs. No data passes through PAPI servers.

How It Works

Your App → PAPI SDK → Exchange (Polymarket/Kalshi)

The SDK handles exchange-specific authentication, request formatting, and response normalization locally. You provide credentials directly.

Setup

Polymarket

Polymarket uses the CLOB API with API key, secret, and passphrase:

use papi_sdk::{PapiConfig, PapiClient, Exchange};

let config = PapiConfig::direct()
    .polymarket_credentials(
        "your-clob-api-key",
        "your-clob-secret",
        "your-passphrase",
    )
    .build()?;

let client = PapiClient::new(config);

let markets = client
    .markets(Exchange::Polymarket)
    .active(true)
    .send()
    .await?;

Kalshi

Kalshi uses email/password authentication with session tokens:

let config = PapiConfig::direct()
    .kalshi_credentials(
        "your-email@example.com",
        "your-password",
    )
    .build()?;

let client = PapiClient::new(config);

let markets = client
    .markets(Exchange::Kalshi)
    .status("open")
    .send()
    .await?;

Both Exchanges

let config = PapiConfig::direct()
    .polymarket_credentials("key", "secret", "passphrase")
    .kalshi_credentials("email", "password")
    .build()?;

Environment Variables

Instead of hardcoding credentials:

export PAPI_MODE=direct
export POLYMARKET_API_KEY=your-clob-api-key
export POLYMARKET_SECRET=your-clob-secret
export POLYMARKET_PASSPHRASE=your-passphrase
export KALSHI_EMAIL=your-email@example.com
export KALSHI_PASSWORD=your-password
let config = PapiConfig::from_env()?;

When to Use Direct Mode

Direct mode is best when:

  • Latency matters — Eliminates the proxy hop through PAPI servers
  • Credential control — You want credentials to stay on your infrastructure
  • Offline operation — Your app should work even if PAPI servers are down
  • High throughput — You need more than 60 requests per minute

Trade-offs

FeatureManagedDirect
Credential storageServer-side (encrypted)Client-side
CachingBuilt-in (PostgreSQL)None (bring your own)
Rate limiting60 req/min per keyExchange limits apply
Latency+10-50ms (proxy hop)Direct to exchange
Auth complexityOne API keyPer-exchange credentials
PAPI dependencyRequiredNot required

Switching Modes

Since both modes use the same SDK interface, switching is a config change:

// Managed mode
let config = PapiConfig::managed()
    .api_key("papi_sk_live_...")
    .build()?;

// Direct mode — same client API
let config = PapiConfig::direct()
    .polymarket_credentials("key", "secret", "pass")
    .build()?;

// Client code stays the same
let client = PapiClient::new(config);
let markets = client.markets(Exchange::Polymarket).send().await?;

On this page