Skip to content

Authentication

UltimaLotto supports multiple authentication methods for different use cases.

API Key Authentication

For server-to-server SDK integration, use your API key in the X-Ultima-Key header.

API keys are formatted as ulk_ followed by 32 hex characters (e.g., ulk_a1b2c3d4e5f6...).

Example

typescript
const response = await fetch("https://api.ultimalotto.com/api/operator/me", {
  headers: {
    "X-Ultima-Key": "ulk_your_api_key_here",
  },
});

Using the SDK

The Operator SDK automatically handles API key authentication:

typescript
const client = new CoordinatorClient({
  coordinatorUrl: "https://api.ultimalotto.com",
  apiKey: "ulk_your_api_key_here",
  maxRetries: 3,
  requestTimeoutMs: 10_000,
});

JWT Authentication

For browser-based dashboards and portals, use JWT tokens. Access tokens expire in 15 minutes; refresh tokens last 7 days and are single-use.

Login Flow

typescript
// Exchange API key for JWT pair
const loginRes = await fetch("https://api.ultimalotto.com/api/auth/operator/login", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ apiKey: "ulk_your_api_key_here" }),
});
const { accessToken, refreshToken, expiresIn } = await loginRes.json();

Using Access Token

typescript
const response = await fetch("https://api.ultimalotto.com/api/operator/me", {
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

Refresh Token

typescript
const refreshRes = await fetch("https://api.ultimalotto.com/api/auth/refresh", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ refreshToken }),
});
const { accessToken, refreshToken } = await refreshRes.json();
// Old refresh token is revoked; use the new one for next refresh

Logout

typescript
await fetch("https://api.ultimalotto.com/api/auth/logout", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ refreshToken }),
});

Webhook Signature Verification

All webhooks are signed with HMAC-SHA256. Verify the X-Ultima-Signature header before processing.

Verification

typescript
import { createHmac } from "node:crypto";

function verifyWebhookSignature(
  rawBody: string,
  signature: string,
  apiKey: string
): boolean {
  const expected = createHmac("sha256", apiKey)
    .update(rawBody)
    .digest("hex");
  return signature === expected;
}

// In your webhook handler
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.headers["x-ultima-signature"] as string;
  const rawBody = req.body.toString();

  if (!verifyWebhookSignature(rawBody, signature, process.env.ULTIMA_API_KEY!)) {
    res.status(401).send("Invalid signature");
    return;
  }

  const payload = JSON.parse(rawBody);
  // Process payload...
  res.status(200).send("OK");
});

Important

Always use the raw request body for signature verification. Parsing JSON or modifying the body will invalidate the signature.