GuidesTrading

Authentication

Authenticate your requests with an API key, and get a JWT for the endpoints that act for a wallet.

Predict's API uses two credentials:

CredentialHeaderNeeded for
API keyx-api-key: <key>Every request on mainnet.
JWTAuthorization: Bearer <jwt>Requests that act for a wallet, such as creating and removing orders or reading its own orders.

API key

Create an API key in the developer console. Send it in the x-api-key header of every mainnet request. A request without a valid key gets a 401.

Testnet (https://api-testnet.predict.fun) needs no key. Leave the header out there, because testnet still rejects an invalid key.

The WebSocket API takes the same key, in the x-api-key header or the apiKey query parameter. See WebSocket API. Each key has its own rate limits.

Get a JWT

A JWT proves that you control a wallet. You get one in three steps:

  1. Get a message to sign from GET /v1/auth/message.
  2. Sign the message with the wallet.
  3. Send the message, the signature and the wallet's address to POST /v1/auth. The response holds the JWT in data.token.

The message ends with a timestamp. Sign and send it within 10 minutes, or the login is rejected. A JWT is valid for 24 hours. After that, log in again.

With a wallet

Sign the message as a personal message (EIP-191) with the wallet's private key. The signer is the wallet's address.

import { Wallet } from "ethers";

const apiKey = "YOUR_API_KEY";
const wallet = new Wallet(process.env.WALLET_PRIVATE_KEY!);

// 1. Get the message to sign.
const messageResponse = await fetch("https://api.predict.fun/v1/auth/message", {
  headers: { "x-api-key": apiKey },
});
const { message } = (await messageResponse.json()).data;

// 2. Sign it with the wallet.
const signature = await wallet.signMessage(message);

// 3. Exchange the signature for a JWT.
const jwtResponse = await fetch("https://api.predict.fun/v1/auth", {
  method: "POST",
  headers: { "Content-Type": "application/json", "x-api-key": apiKey },
  body: JSON.stringify({ signer: wallet.address, message, signature }),
});
if (!jwtResponse.ok) throw new Error(`Login failed: ${jwtResponse.status}`);
const { token } = (await jwtResponse.json()).data;
console.log(token);

With a Predict account

A Predict account is the smart wallet that the web app creates for you. Its address is your deposit address, and it holds your funds. Your Privy wallet signs for it. You can export the Privy wallet's private key from your account settings.

For a Predict account, two things change:

  • The signature must come from the SDK's Predict account signing. A plain wallet signature is rejected.
  • The signer is the Predict account's address, not the Privy wallet's.

When you create the order builder with a Predict account, the SDK checks on-chain that the Privy wallet owns that account. If it doesn't, the builder fails with "The signer is not the owner of the Predict account". This also happens when the account was never set up in the web app.

import { ChainId, OrderBuilder } from "@predictdotfun/sdk";
import { Wallet } from "ethers";

const apiKey = "YOUR_API_KEY";
// the Predict account's address, also called its deposit address.
const predictAccount = "PREDICT_ACCOUNT_ADDRESS";
// the Privy wallet, whose key you export from https://predict.fun/account/settings
const privyWallet = new Wallet(process.env.PRIVY_WALLET_PRIVATE_KEY!);

// the order builder signs for the Predict account with the Privy wallet.
const orderBuilder = await OrderBuilder.make(ChainId.BnbMainnet, privyWallet, {
  predictAccount,
});

const messageResponse = await fetch("https://api.predict.fun/v1/auth/message", {
  headers: { "x-api-key": apiKey },
});
const { message } = (await messageResponse.json()).data;

// a Predict account needs this signature. A plain wallet signature is rejected.
const signature = await orderBuilder.signPredictAccountMessage(message);

const jwtResponse = await fetch("https://api.predict.fun/v1/auth", {
  method: "POST",
  headers: { "Content-Type": "application/json", "x-api-key": apiKey },
  body: JSON.stringify({ signer: predictAccount, message, signature }),
});
if (!jwtResponse.ok) throw new Error(`Login failed: ${jwtResponse.status}`);
const { token } = (await jwtResponse.json()).data;
console.log(token);

Keep private keys on a server you control. Never put one in code that runs in a browser.

Send the credentials

Send both headers on requests that act for a wallet:

{
  "x-api-key": "YOUR_API_KEY",
  "Authorization": "Bearer YOUR_JWT"
}

Each REST reference page lists the credentials its endpoint needs. For live order updates over the WebSocket, the JWT goes in the topic name instead. See Order lifecycle.

On this page