IZI SDK Examples: JavaScript and Python
IZI SDK Examples: JavaScript and Python
Section titled “IZI SDK Examples: JavaScript and Python”There’s no official IZI SDK — the API is standard GraphQL and works with any HTTP client. Here are production-ready wrapper classes for Node.js and Python with authentication, automatic token refresh, and error handling built in.
JavaScript / Node.js
Section titled “JavaScript / Node.js”Dependencies
Section titled “Dependencies”npm install graphql-request graphqlIZIClient Class
Section titled “IZIClient Class”const { GraphQLClient, gql } = require('graphql-request');
const API_URL = 'https://api.izi.is/graphql';
class IZIClient { constructor() { this.client = new GraphQLClient(API_URL); this.accessToken = null; this.refreshToken = null; this.tokenExpiresAt = null; }
async login(email, password) { const mutation = gql` mutation Login($email: String!, $password: String!) { loginWithEmailPassword(email: $email, password: $password) { accessToken refreshToken } } `;
const data = await this.client.request(mutation, { email, password }); this._setTokens(data.loginWithEmailPassword); return data.loginWithEmailPassword; }
async _refreshTokens() { const mutation = gql` mutation Refresh($token: String!) { refreshToken(token: $token) { accessToken refreshToken } } `;
const data = await this.client.request(mutation, { token: this.refreshToken, }); this._setTokens(data.refreshToken); }
_setTokens({ accessToken, refreshToken }) { this.accessToken = accessToken; this.refreshToken = refreshToken; // accessToken lives 15 min, refresh 2 min before expiry this.tokenExpiresAt = Date.now() + 13 * 60 * 1000; this.client.setHeader('Authorization', `Bearer ${accessToken}`); }
async request(query, variables = {}) { if (this.tokenExpiresAt && Date.now() > this.tokenExpiresAt) { await this._refreshTokens(); }
try { return await this.client.request(query, variables); } catch (error) { const code = error.response?.errors?.[0]?.extensions?.code;
if (code === 'TOKEN_EXPIRED') { await this._refreshTokens(); return await this.client.request(query, variables); }
throw error; } }}
module.exports = IZIClient;const IZIClient = require('./izi-client');const { gql } = require('graphql-request');
async function main() { const izi = new IZIClient();
await izi.login( process.env.IZI_EMAIL, process.env.IZI_PASSWORD );
// Get list of clubs const { clubs } = await izi.request(gql` query GetClubs { clubs { id name timezone } } `);
console.log('Clubs:', clubs);
// Get active sessions const { activeSessions } = await izi.request( gql` query ActiveSessions($clubId: ID!) { activeSessions(clubId: $clubId) { id deviceName clientName startedAt balance } } `, { clubId: clubs[0].id } );
console.log('Active sessions:', activeSessions.length);}
main().catch(console.error);Webhook Handler
Section titled “Webhook Handler”const express = require('express');const crypto = require('crypto');
const app = express();const WEBHOOK_SECRET = process.env.IZI_WEBHOOK_SECRET;
app.post( '/izi/events', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-izi-signature']; const expected = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(req.body) .digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) { return res.status(401).json({ error: 'Invalid signature' }); }
const event = JSON.parse(req.body); console.log(`Event: ${event.type}`, event.data);
switch (event.type) { case 'SESSION_ENDED': handleSessionEnded(event.data); break; case 'BALANCE_TOPPED_UP': handleTopUp(event.data); break; }
res.status(200).send('OK'); });
app.listen(3000, () => console.log('Webhook server on :3000'));Apollo Client (React / Next.js)
Section titled “Apollo Client (React / Next.js)”import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';import { setContext } from '@apollo/client/link/context';
const httpLink = createHttpLink({ uri: 'https://api.izi.is/graphql',});
const authLink = setContext((_, { headers }) => { const token = localStorage.getItem('izi_access_token'); return { headers: { ...headers, authorization: token ? `Bearer ${token}` : '', }, };});
export const client = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache(),});Python
Section titled “Python”Dependencies
Section titled “Dependencies”pip install gql[httpx] httpxIZIClient Class
Section titled “IZIClient Class”import timeimport hmacimport hashlibfrom gql import gql, Clientfrom gql.transport.httpx import HTTPXTransport
API_URL = "https://api.izi.is/graphql"
class IZIClient: def __init__(self): self.access_token = None self.refresh_token = None self.token_expires_at = 0 self._transport = None self._client = None
def _build_client(self): headers = {} if self.access_token: headers["Authorization"] = f"Bearer {self.access_token}"
self._transport = HTTPXTransport(url=API_URL, headers=headers) self._client = Client(transport=self._transport, fetch_schema_from_transport=False)
def login(self, email: str, password: str) -> dict: self._build_client() mutation = gql(""" mutation Login($email: String!, $password: String!) { loginWithEmailPassword(email: $email, password: $password) { accessToken refreshToken } } """)
result = self._client.execute(mutation, {"email": email, "password": password}) tokens = result["loginWithEmailPassword"] self._set_tokens(tokens) return tokens
def _refresh_tokens(self): self._build_client() mutation = gql(""" mutation Refresh($token: String!) { refreshToken(token: $token) { accessToken refreshToken } } """) result = self._client.execute(mutation, {"token": self.refresh_token}) self._set_tokens(result["refreshToken"])
def _set_tokens(self, tokens: dict): self.access_token = tokens["accessToken"] self.refresh_token = tokens["refreshToken"] # Refresh 2 minutes before expiry (TTL 15 min) self.token_expires_at = time.time() + 13 * 60 self._build_client()
def request(self, query_str: str, variables: dict = None) -> dict: if self.token_expires_at and time.time() > self.token_expires_at: self._refresh_tokens()
query = gql(query_str) return self._client.execute(query, variables or {})import osfrom izi_client import IZIClient
def main(): izi = IZIClient() izi.login( email=os.environ["IZI_EMAIL"], password=os.environ["IZI_PASSWORD"] )
result = izi.request(""" query GetClubs { clubs { id name timezone } } """) clubs = result["clubs"] print(f"Clubs: {len(clubs)}")
sessions = izi.request(""" query ActiveSessions($clubId: ID!) { activeSessions(clubId: $clubId) { id deviceName clientName startedAt } } """, {"clubId": clubs[0]["id"]})
print(f"Active sessions: {len(sessions['activeSessions'])}")
if __name__ == "__main__": main()Webhook Signature Verification (Python)
Section titled “Webhook Signature Verification (Python)”import osimport hmacimport hashlibfrom flask import Flask, request, abort
app = Flask(__name__)WEBHOOK_SECRET = os.environ["IZI_WEBHOOK_SECRET"]
def verify_signature(payload: bytes, signature: str, secret: str) -> bool: expected = hmac.new( secret.encode(), payload, hashlib.sha256 ).hexdigest() return hmac.compare_digest(signature, expected)
@app.post("/izi/events")def handle_event(): signature = request.headers.get("X-IZI-Signature", "")
if not verify_signature(request.data, signature, WEBHOOK_SECRET): abort(401)
event = request.get_json(force=True) print(f"Event: {event['type']}", event.get("data"))
match event["type"]: case "SESSION_ENDED": handle_session_ended(event["data"]) case "BALANCE_TOPPED_UP": handle_top_up(event["data"])
return "OK", 200Environment Variables
Section titled “Environment Variables”For both examples, use a .env file:
IZI_EMAIL=partner@example.comIZI_PASSWORD=your_secure_passwordIZI_WEBHOOK_SECRET=your_webhook_secretNever store tokens or passwords in the repository code.
Related Pages
Section titled “Related Pages”- IZI API: Overview — general architecture
- Authentication & Tokens — JWT auth details
- Webhooks — full webhooks guide
- API Error Codes — error code reference
Frequently asked questions
Is there an official IZI SDK?
There is no official package. IZI API is standard GraphQL and works with any GraphQL library: graphql-request, Apollo Client, gql + httpx. The examples below cover the main scenarios.
What dependencies are needed for Node.js integration?
Minimal: graphql-request. For production, add node-cron (token rotation) and pino or winston for logging.
How do I pass a token to Apollo Client?
Use authLink from @apollo/client/link/context. Example in the Apollo Client section below.