Skip to main content

Overview

Bayse Markets API uses API key authentication with HMAC-SHA256 signatures for secure request verification. Authentication requirements vary by endpoint:
  • Public endpoints: No authentication required.
  • Read endpoints: API key only (X-Public-Key header).
  • Write endpoints: API key + timestamp + HMAC signature.

API key structure

API keys come in pairs:
  • Public key (pk_*): Identifies your API key (safe to expose in headers).
  • Secret key (sk_*): Used to sign requests (keep secure, never expose).
Public key:  pk_live_abcdef123456
Secret key:  sk_live_secret789xyz
Your secret key is only shown once during creation. Store it securely in environment variables or a secrets manager.

Authentication levels

Public endpoints

Some endpoints require no authentication:
curl https://relay.bayse.markets/health

Read authentication

For read operations, include your public key in the X-Public-Key header:
curl -X GET "https://relay.bayse.markets/v1/pm/events" \
  -H "X-Public-Key: pk_live_abcdef123456"
Endpoints requiring read authentication:
  • GET /v1/pm/portfolio.
  • GET /v1/pm/orders.
  • GET /v1/pm/activities.

Write authentication

Write operations require three headers:
  1. X-Public-Key: Your public API key.
  2. X-Timestamp: Current Unix timestamp (seconds).
  3. X-Signature: HMAC-SHA256 signature of the request payload (base64-encoded).
The signing payload format is: {timestamp}.{METHOD}.{path}.{bodyHash}
  • timestamp: The same Unix timestamp sent in X-Timestamp.
  • METHOD: The HTTP method in uppercase (e.g., POST, DELETE).
  • path: The request path (e.g., /v1/pm/orders/abc123).
  • bodyHash: SHA-256 hex digest of the request body. Empty string if there is no body.
PUBLIC_KEY="pk_live_abcdef123456"
SECRET_KEY="sk_live_secret789xyz"
TIMESTAMP=$(date +%s)
METHOD="POST"
URL_PATH="/v1/pm/events/evt_123/markets/mkt_456/orders"
BODY='{"side":"BUY","outcome":"YES","amount":100,"currency":"USD"}'

# Compute body hash (SHA-256 hex digest; empty string if no body)
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex 2>/dev/null | sed 's/.*= //')

# Build signing payload
PAYLOAD="${TIMESTAMP}.${METHOD}.${URL_PATH}.${BODY_HASH}"

# Create HMAC-SHA256 signature (base64-encoded)
SIGNATURE=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET_KEY" -binary | base64)

curl -X POST "https://relay.bayse.markets${URL_PATH}" \
  -H "X-Public-Key: ${PUBLIC_KEY}" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Signature: ${SIGNATURE}" \
  -H "Content-Type: application/json" \
  -d "$BODY"
Endpoints requiring write authentication:
  • POST /v1/pm/events/{eventId}/markets/{marketId}/orders.
  • DELETE /v1/pm/orders/{orderId}.

Implementing HMAC signatures

How it works

  1. Get the current Unix timestamp (seconds since epoch).
  2. Build the signing payload: {timestamp}.{METHOD}.{path}.{bodyHash}.
    • If the request has a JSON body, bodyHash is the SHA-256 hex digest of the raw body bytes.
    • If there is no body, bodyHash is an empty string (the payload ends with a trailing .).
  3. Compute the HMAC-SHA256 of the payload using your secret key.
  4. Base64-encode the result.
  5. Send in the X-Signature header along with X-Timestamp.
The server verifies the signature matches and the timestamp is within a 5-minute window (prevents replay attacks).

Code examples

PUBLIC_KEY="pk_live_abcdef123456"
SECRET_KEY="sk_live_secret789xyz"
TIMESTAMP=$(date +%s)
METHOD="POST"
URL_PATH="/v1/pm/events/evt_123/markets/mkt_456/orders"
BODY='{"side":"BUY","outcome":"YES","amount":100,"currency":"USD"}'

# Compute body hash (SHA-256 hex digest)
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 -hex 2>/dev/null | sed 's/.*= //')

# Build signing payload and create HMAC-SHA256 signature
PAYLOAD="${TIMESTAMP}.${METHOD}.${URL_PATH}.${BODY_HASH}"
SIGNATURE=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET_KEY" -binary | base64)

# Make authenticated request
curl -X POST "https://relay.bayse.markets${URL_PATH}" \
  -H "X-Public-Key: ${PUBLIC_KEY}" \
  -H "X-Timestamp: ${TIMESTAMP}" \
  -H "X-Signature: ${SIGNATURE}" \
  -H "Content-Type: application/json" \
  -d "$BODY"

Social sign-in users

If you signed up for Bayse using Apple or Google, your account doesn’t have a password yet. The API requires email and password authentication to create and manage API keys. To set up a password:
  1. Open the Bayse app and go to Forgot Password (or use the password reset flow).
  2. Enter the email associated with your Apple/Google account.
  3. Follow the instructions to create a password.
Once you’ve set a password, you can use it with the login endpoint to get a session token and start managing API keys.
Setting a password does not change or remove your existing sign-in method. You can continue using Apple or Google to sign in to the Bayse app as usual. The password is only needed for API access.
There is currently no web UI for managing API keys — all key management is done through the API. See the Quickstart guide to get started.

Managing API keys

Getting a session token

Before you can create or manage API keys, you need to log in with your Bayse account credentials to get a session token and device ID:
curl -X POST https://relay.bayse.markets/v1/user/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "you@example.com",
    "password": "your-password"
  }'
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "deviceId": "d_abc123",
  "userId": "usr_456def"
}
Use the token and deviceId from the response as the x-auth-token and x-device-id headers for all API key management requests below.
The login endpoint is rate-limited to 1 request per 2 minutes per email address. Cache your session token and reuse it. See Rate limits for details.

Creating API keys

With your session token and device ID, create an API key:
curl -X POST https://relay.bayse.markets/v1/user/me/api-keys \
  -H "x-auth-token: YOUR_TOKEN" \
  -H "x-device-id: YOUR_DEVICE_ID" \
  -H "Content-Type: application/json" \
  -d '{"name": "Production API Key"}'
{
  "id": "key_abc123",
  "publicKey": "pk_live_abcdef123456",
  "secretKey": "sk_live_secret789xyz",
  "name": "Production API Key",
  "createdAt": "2026-02-16T10:30:00Z"
}

Listing API keys

curl -X GET https://relay.bayse.markets/v1/user/me/api-keys \
  -H "x-auth-token: YOUR_TOKEN" \
  -H "x-device-id: YOUR_DEVICE_ID"

Revoking API keys

curl -X DELETE https://relay.bayse.markets/v1/user/me/api-keys/key_abc123 \
  -H "x-auth-token: YOUR_TOKEN" \
  -H "x-device-id: YOUR_DEVICE_ID"

Rotating API keys

Generate a new secret key while keeping the same public key:
curl -X POST https://relay.bayse.markets/v1/user/me/api-keys/key_abc123/rotate \
  -H "x-auth-token: YOUR_TOKEN" \
  -H "x-device-id: YOUR_DEVICE_ID"
{
  "id": "key_abc123",
  "publicKey": "pk_live_abcdef123456",
  "secretKey": "sk_live_newsecret456def",
  "name": "Production API Key",
  "rotatedAt": "2026-02-16T11:00:00Z"
}

Security best practices

  • Never commit API keys to version control
  • Use environment variables or secrets managers
  • Rotate keys regularly
  • Use separate keys for development and production
  • Never expose secret keys in client-side code
  • Don’t log secret keys
  • Revoke compromised keys immediately
  • The secret key is only shown once - save it during creation
  • Don’t expose secret keys in error messages
  • Handle authentication errors gracefully
  • Implement retry logic with exponential backoff
  • Monitor for suspicious authentication patterns
  • Always use HTTPS in production
  • Verify SSL certificates
  • Never send credentials over HTTP

Common errors

Invalid signature

{
  "error": "invalid_signature",
  "message": "The provided signature does not match the expected signature"
}
Causes:
  • Incorrect secret key.
  • Timestamp mismatch (signed different timestamp than sent in X-Timestamp).
  • Wrong payload format — must be {timestamp}.{METHOD}.{path}.{bodyHash}.
  • Body hash mismatch — the exact bytes sent in the request body must match what was hashed when signing. Avoid trimming or reformatting the body after signing.
  • Incorrect HMAC algorithm (must be SHA-256).
  • Incorrect encoding (signature must be base64, body hash must be hex).

Timestamp too old

{
  "error": "timestamp_expired",
  "message": "Request timestamp is too old"
}
Cause: The timestamp in X-Timestamp is too far in the past. Ensure your system clock is synchronized.

Missing API key

{
  "error": "unauthorized",
  "message": "API key is required for this endpoint"
}
Cause: The X-Public-Key header is missing or invalid.

Next steps

API reference

Explore all available endpoints

Prediction markets

Learn about prediction market operations

User endpoints

Manage your API keys programmatically