### Build and Run Android Quick Start Source: https://docs.january.ai/android-sdk/getting-started/quick-start.md Use Gradle to install the debug build with required tokens and launch the main activity using ADB. ```bash ./gradlew :app:installDebug \ -PjanuaryTokenUrl=https://your-backend.example/january-token \ -PpartnerSessionToken=YOUR_APP_SESSION_TOKEN \ -PjanuaryEndUserId=YOUR_STABLE_USER_ID adb shell am start -n \ com.example.januaryquickstart/.MainActivity ``` -------------------------------- ### Install and configure dependencies Source: https://docs.january.ai/web-sdk/getting-started/example-app.md Navigate to the demo directory and install required packages. ```bash cd examples/react-demo npm ci ``` -------------------------------- ### Build and Install Demo App Source: https://docs.january.ai/android-sdk/getting-started/example-app.md Use these Gradle commands to run unit tests, assemble the debug build, and install the application on a connected device. ```bash ./gradlew :demo:testDebugUnitTest :demo:assembleDebug ./gradlew :demo:installDebug ``` -------------------------------- ### Run and verify the application Source: https://docs.january.ai/web-sdk/getting-started/example-app.md Commands to test, build, and start the development server. ```bash npm test npm run build npm run dev ``` -------------------------------- ### Locate the Example Project Source: https://docs.january.ai/ios-sdk/getting-started/example-app.md Path to the Xcode project file for the native SwiftUI demo application. ```text Examples/JanuaryPartnerDemo/JanuaryPartnerDemo.xcodeproj ``` -------------------------------- ### GET /docs/quickstart.md Source: https://docs.january.ai/llms.txt Performs a natural language query against the documentation index to retrieve an answer and relevant sources. ```APIDOC ## GET /docs/quickstart.md ### Description Perform an HTTP GET request on the documentation index with the `ask` parameter, and the optional `goal` parameter to retrieve answers and relevant excerpts from the documentation. ### Method GET ### Endpoint https://docs.january.ai/docs/quickstart.md ### Parameters #### Query Parameters - **ask** (string) - Required - The immediate question to ask, written in natural language. - **goal** (string) - Optional - Describes the broader end goal to help tailor the answer. ### Request Example GET https://docs.january.ai/docs/quickstart.md?ask=How do I authenticate?&goal=Setting up the SDK ``` -------------------------------- ### Query documentation via HTTP GET Source: https://docs.january.ai/llms.txt Perform a GET request to the documentation index with specific query parameters to receive a direct answer and relevant excerpts. ```http GET https://docs.january.ai/docs/quickstart.md?ask=&goal= ``` -------------------------------- ### Install January Web SDK via npm Source: https://docs.january.ai/web-sdk/getting-started/installation.md Use this command to add the SDK to your project dependencies. ```bash npm install @januaryai/web-sdk ``` -------------------------------- ### Invoke January Quick Start Function Source: https://docs.january.ai/web-sdk/getting-started/quick-start.md Executes the exported rendering function once the DOM element is available. ```ts import { renderJanuaryQuickStart } from './january-quickstart'; const output = document.querySelector('#january-results'); if (output) { void renderJanuaryQuickStart(output).catch(() => { // renderJanuaryQuickStart already logs the typed January error details. }); } ``` -------------------------------- ### GET /v1.2/foods Source: https://docs.january.ai/rest-api/foods.md Search the January food database. ```APIDOC ## GET /v1.2/foods ### Description Search the January food database. ### Method GET ### Endpoint /v1.2/foods ``` -------------------------------- ### get Source: https://docs.january.ai/ios-sdk/reference/foods-api.md Retrieves a complete food item by its ID. ```APIDOC ## get(id: FoodID, endUserID: PartnerUserID?) ### Description Fetches a single, complete FoodSearchItem including all serving information. ### Method Swift SDK Method ### Parameters - **id** (FoodID) - Required - The unique identifier for the food item. - **endUserID** (PartnerUserID?) - Optional - The ID of the end user. ``` -------------------------------- ### Configure JanuaryQuickstartApp.swift Source: https://docs.january.ai/ios-sdk/getting-started/quick-start.md Defines the main entry point for the SwiftUI application. ```swift import SwiftUI @main struct JanuaryQuickstartApp: App { var body: some Scene { WindowGroup { ContentView() } } } ``` -------------------------------- ### get(request) Source: https://docs.january.ai/web-sdk/reference/user-resources-api.md Retrieves a specific food log by ID. ```APIDOC ## get(request) ### Description Retrieves details for a specific food log entry. ### Parameters - **logId** (string) - Required - The ID of the food log. - **signal** (AbortSignal) - Optional - AbortSignal for request cancellation. ### Response - **FoodLog** (Object) - The requested food log. ``` -------------------------------- ### GET /v1.2/food-logs Source: https://docs.january.ai/rest-api/food-logs.md Retrieves a list of food log entries. ```APIDOC ## GET /v1.2/food-logs ### Description Retrieves a list of food log entries for the user. ### Method GET ### Endpoint /v1.2/food-logs ``` -------------------------------- ### Verify SDK checkout and package Source: https://docs.january.ai/web-sdk/reference/testing-and-support.md Run these commands to ensure the SDK environment is correctly configured and the package builds successfully. ```bash npm ci npm test npm run build npm pack --dry-run npm run demo:web:build ``` -------------------------------- ### GET /v1.2/foods/autocomplete Source: https://docs.january.ai/rest-api/foods.md Power type-ahead results for food searches. ```APIDOC ## GET /v1.2/foods/autocomplete ### Description Power type-ahead results for food searches. ### Method GET ### Endpoint /v1.2/foods/autocomplete ``` -------------------------------- ### Initialize JanuaryClient and List Food Logs Source: https://docs.january.ai/ios-sdk/guides/food-logs.md Initialize the client with a partner user ID and token provider, then retrieve logs for a specific date range. ```swift let client = try JanuaryClient( endUserID: partnerUserID, clientTokenProvider: tokenProvider ) let logs = try await client.foodLogs.list(start: "2026-08-01", end: "2026-08-31") ``` -------------------------------- ### Build iOS Project via Command Line Source: https://docs.january.ai/ios-sdk/getting-started/quick-start.md Compiles the JanuaryQuickstart project using xcodebuild for the iOS Simulator. ```sh xcodebuild \ -project JanuaryQuickstart.xcodeproj \ -scheme JanuaryQuickstart \ -sdk iphonesimulator \ -destination 'generic/platform=iOS Simulator' \ CODE_SIGNING_ALLOWED=NO \ build ``` -------------------------------- ### GET /v1.2/foods/barcode/{barcode} Source: https://docs.january.ai/rest-api/foods.md Look up food details using a barcode. ```APIDOC ## GET /v1.2/foods/barcode/{barcode} ### Description Look up food details using a barcode. ### Method GET ### Endpoint /v1.2/foods/barcode/{barcode} ### Parameters #### Path Parameters - **barcode** (string) - Required - The barcode of the food item. ``` -------------------------------- ### Implement MainActivity and Token Provider Source: https://docs.january.ai/android-sdk/getting-started/quick-start.md Sets up the JanuaryPartnerClient with a custom token provider and performs a sample food search. ```kotlin package com.example.januaryquickstart import ai.january.partner.JanuaryClientToken import ai.january.partner.JanuaryException import ai.january.partner.JanuaryPartnerClient import ai.january.partner.JanuaryTokenProvider import ai.january.partner.JanuaryTokenProviderException import ai.january.partner.PartnerUserId import ai.january.partner.foods.SearchFoodsRequest import android.app.Activity import android.os.Bundle import android.widget.TextView import java.net.HttpURLConnection import java.net.URL import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.launch import kotlinx.coroutines.withContext private class PartnerBackendTokenProvider( endpoint: String, private val sessionToken: String, ) : JanuaryTokenProvider { private val endpointUrl = URL(endpoint) override suspend fun fetchClientToken(): JanuaryClientToken = withContext(Dispatchers.IO) { val connection = (endpointUrl.openConnection() as HttpURLConnection).apply { requestMethod = "GET" connectTimeout = 10_000 readTimeout = 10_000 setRequestProperty("Accept", "application/json") setRequestProperty("Authorization", "Bearer $sessionToken") } try { val status = connection.responseCode if (status !in 200..299) { throw JanuaryTokenProviderException( "Token endpoint returned HTTP $status", retryable = status == 408 || status == 429 || status >= 500, ) } val json = connection.inputStream.bufferedReader().use { it.readText() } JanuaryClientToken.fromJson(json) } finally { connection.disconnect() } } } class MainActivity : Activity() { private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val output = TextView(this).apply { text = "Connecting…" textSize = 18f setPadding(40, 80, 40, 40) } setContentView(output) require(BuildConfig.JANUARY_TOKEN_URL.isNotBlank()) { "Pass -PjanuaryTokenUrl=https://your-backend.example/january-token" } require(BuildConfig.PARTNER_SESSION_TOKEN.isNotBlank()) { "Pass -PpartnerSessionToken=" } require(BuildConfig.JANUARY_END_USER_ID.isNotBlank()) { "Pass -PjanuaryEndUserId=" } val january = JanuaryPartnerClient.withClientTokenProvider( PartnerBackendTokenProvider( endpoint = BuildConfig.JANUARY_TOKEN_URL, sessionToken = BuildConfig.PARTNER_SESSION_TOKEN, ), ) val user = january.forUser( endUserId = PartnerUserId(BuildConfig.JANUARY_END_USER_ID), timezone = java.util.TimeZone.getDefault().id, ) scope.launch { try { val response = user.foods.search( SearchFoodsRequest(query = "greek yogurt", limit = 5), ) output.text = buildString { appendLine("Connected") response.items.forEach { appendLine("• ${it.name}") } } } catch (error: JanuaryException) { output.text = "January ${error.category}: ${error.message}" } catch (error: Exception) { output.text = "Integration error: ${error.message}" } } } override fun onDestroy() { scope.cancel() super.onDestroy() } } ``` -------------------------------- ### GET /v1.2/menu-items Source: https://docs.january.ai/rest-api/restaurants.md Search for dishes across restaurants near a location. ```APIDOC ## GET /v1.2/menu-items ### Description Search dishes across restaurants near a location. ### Method GET ### Endpoint /v1.2/menu-items ``` -------------------------------- ### GET /v1.2/restaurants Source: https://docs.january.ai/rest-api/restaurants.md Retrieve a list of restaurants near a specified location. ```APIDOC ## GET /v1.2/restaurants ### Description Find restaurants near a location. ### Method GET ### Endpoint /v1.2/restaurants ``` -------------------------------- ### Initialize JanuaryClient for local development Source: https://docs.january.ai/web-sdk/getting-started/authentication.md Use a development API key for local testing only. Never include this in production bundles or commit the key to version control. ```ts const developmentApiKey = import.meta.env.VITE_JANUARY_DEVELOPMENT_API_KEY; if (!developmentApiKey) { throw new Error('Missing VITE_JANUARY_DEVELOPMENT_API_KEY in local configuration'); } const january = new JanuaryClient({ developmentApiKey, }); ``` -------------------------------- ### Initialize JanuaryPartnerClient Source: https://docs.january.ai/android-sdk/reference/client-and-resources.md Constructors for the public entry point using either a fixed token or a token provider. ```kotlin JanuaryPartnerClient.withClientToken(clientToken: String): JanuaryPartnerClient JanuaryPartnerClient.withClientTokenProvider( provider: JanuaryTokenProvider, tokenRetryPolicy: JanuaryTokenRetryPolicy = JanuaryTokenRetryPolicy(), ): JanuaryPartnerClient fun interface JanuaryTokenProvider { suspend fun fetchClientToken(): JanuaryClientToken } data class JanuaryClientToken( val token: String, val expiresIn: Long, ) ``` -------------------------------- ### get(id:) Source: https://docs.january.ai/ios-sdk/reference/food-logs-api.md Retrieves a specific food log by its unique identifier. ```APIDOC ## get(id: String) ### Description Fetches a single food log entry by ID. Returns a .notFound error if the log does not exist. ### Parameters - **id** (String) - Required - The unique identifier of the food log. ### Returns - **FoodLog** - The requested food log object. ``` -------------------------------- ### GET /v1.2/food-logs/{log_id} Source: https://docs.january.ai/rest-api/food-logs.md Retrieves a specific food log entry by its identifier. ```APIDOC ## GET /v1.2/food-logs/{log_id} ### Description Retrieves details for a specific food log entry. ### Method GET ### Endpoint /v1.2/food-logs/{log_id} ### Parameters #### Path Parameters - **log_id** (string) - Required - The unique identifier of the food log entry. ``` -------------------------------- ### GET /v1.2/foods/{food_id} Source: https://docs.january.ai/rest-api/foods.md Hydrate serving details for a specific food item. ```APIDOC ## GET /v1.2/foods/{food_id} ### Description Hydrate serving details for a specific food item. ### Method GET ### Endpoint /v1.2/foods/{food_id} ### Parameters #### Path Parameters - **food_id** (string) - Required - The unique identifier of the food item. ``` -------------------------------- ### Initialize JanuaryClient Source: https://docs.january.ai/ios-sdk/guides/foods.md Configure the client with a stable end-user ID and token provider. ```swift let client = try JanuaryClient( endUserID: partnerUserID, clientTokenProvider: tokenProvider ) ``` -------------------------------- ### Initialize JanuaryClient and perform a food search Source: https://docs.january.ai/ios-sdk/overview.md Initializes the client with a user ID and token provider, then performs an asynchronous search for food items. ```swift import Foundation import January let january = try JanuaryClient( endUserID: signedInUser.id, clientTokenProvider: tokenProvider ) let results = try await january.foods.search(.init(query: "greek yogurt")) ``` -------------------------------- ### get(request: GetFoodRequest) Source: https://docs.january.ai/android-sdk/reference/foods-api.md Retrieves details for a specific food item by ID. ```APIDOC ## suspend fun get(request: GetFoodRequest) ### Description Fetches a single food item by its unique identifier. ### Parameters - **foodId** (FoodId) - Required - The ID of the food. - **endUserId** (PartnerUserId?) - Optional - The user identifier. ``` -------------------------------- ### Initialize JanuaryClient with PartnerBackendTokenProvider Source: https://docs.january.ai/ios-sdk/getting-started/authentication.md Use this function to create a client instance by providing the token endpoint, app session token, and user context. ```swift func makeJanuaryClient( tokenEndpoint: URL, appSessionToken: String, endUserID: String, timezone: TimeZone? = nil ) throws -> JanuaryClient { let provider = PartnerBackendTokenProvider( tokenEndpoint: tokenEndpoint, appSessionToken: appSessionToken ) return try JanuaryClient( endUserID: endUserID, timezone: timezone, clientTokenProvider: provider ) } ``` -------------------------------- ### Verify SDK checkout with Gradle Source: https://docs.january.ai/android-sdk/reference/testing-and-support.md Run these commands to execute unit tests and assemble the release build for the SDK. ```bash ./gradlew :sdk:testDebugUnitTest ./gradlew :sdk:assembleRelease ``` -------------------------------- ### list(start:end:) Source: https://docs.january.ai/ios-sdk/reference/food-logs-api.md Retrieves a list of food logs within a specified date range. ```APIDOC ## list(start: String, end: String) ### Description Retrieves food logs between the provided start and end dates. ### Parameters - **start** (String) - Required - The start date range. - **end** (String) - Required - The end date range. ### Returns - **ListFoodLogsResponse** - Contains totalCount and a list of items. ``` -------------------------------- ### Initialize and use JanuaryClient Source: https://docs.january.ai/ios-sdk/concepts/client-lifecycle.md Create a single instance of JanuaryClient using an end-user ID and token provider, then perform concurrent resource requests. ```swift let client = try JanuaryClient( endUserID: signedInUser.id, clientTokenProvider: tokenProvider ) async let foods = client.foods.search(.init(query: "oatmeal")) async let restaurants = client.restaurants.search( .init(query: "cafe", latitude: 40.7128, longitude: -74.0060) ) let (foodResults, restaurantResults) = try await (foods, restaurants) ``` -------------------------------- ### Initialize JanuaryClient with identity Source: https://docs.january.ai/ios-sdk/concepts/user-identity-and-timezone.md Create the client after authentication using a stable end-user ID and token provider. ```swift let client = try JanuaryClient( endUserID: account.stableID, clientTokenProvider: tokenProvider ) let logs = try await client.foodLogs.list( start: "2026-08-01", end: "2026-08-31" ) let foods = try await client.foods.search( .init(query: "greek yogurt") ) ``` -------------------------------- ### Initialize JanuaryPartnerClient with Token Provider Source: https://docs.january.ai/android-sdk/getting-started/authentication.md Configure the client in your application dependency graph using the custom token provider. ```kotlin import ai.january.partner.JanuaryPartnerClient val january = JanuaryPartnerClient.withClientTokenProvider( provider = PartnerBackendTokenProvider( endpoint = requireNotNull(appConfig.januaryTokenUrl), sessionToken = { sessionRepository.requireAccessToken() }, ), ) ``` -------------------------------- ### GET /v1.2/restaurants/{restaurant_id}/menu-items Source: https://docs.january.ai/rest-api/restaurants.md List a single restaurant's menu using the restaurant ID. ```APIDOC ## GET /v1.2/restaurants/{restaurant_id}/menu-items ### Description List one restaurant's menu by the id a restaurant search returns. ### Method GET ### Endpoint /v1.2/restaurants/{restaurant_id}/menu-items ### Parameters #### Path Parameters - **restaurant_id** (string) - Required - The unique identifier of the restaurant. ``` -------------------------------- ### Clone and verify the SDK repository Source: https://docs.january.ai/android-sdk/getting-started/installation.md Clone the SDK source and run tests to ensure the environment is correctly configured. ```bash git clone https://github.com/January-ai/january-sdk-android.git cd january-sdk-android ./gradlew :sdk:testDebugUnitTest ``` -------------------------------- ### Initialize JanuaryClient Source: https://docs.january.ai/ios-sdk/reference/client-and-resources.md Create a new instance of the JanuaryClient using a user ID and a token provider. ```swift let client = try JanuaryClient( endUserID: signedInUser.id, clientTokenProvider: tokenProvider ) ``` -------------------------------- ### GET /v1.2/credits Source: https://docs.january.ai/rest-api/credits.md Retrieves the current calendar month's API allowance, usage, and reset date. ```APIDOC ## GET /v1.2/credits ### Description Inspect the current calendar month's API allowance, usage, and reset date. ### Method GET ### Endpoint /v1.2/credits ``` -------------------------------- ### Initialize JanuaryClient with environment variables Source: https://docs.january.ai/ios-sdk/getting-started/authentication.md Use this snippet to initialize the client during local development by reading credentials from the Xcode scheme environment. Ensure the JANUARY_API_KEY and JANUARY_END_USER_ID variables are set in your scheme configuration. ```swift import Foundation import January guard let apiKey = ProcessInfo.processInfo.environment["JANUARY_API_KEY"], let endUserID = ProcessInfo.processInfo.environment["JANUARY_END_USER_ID"] else { fatalError("Set the local January development credentials in the Xcode scheme.") } let client = try JanuaryClient( developmentAPIKey: apiKey, endUserID: endUserID ) ``` -------------------------------- ### Initialize JanuaryClient with a token provider Source: https://docs.january.ai/web-sdk/getting-started/authentication.md Use a provider function to fetch tokens from your backend. Ensure the browser origin is enabled and handle retryable errors appropriately. ```ts import { JanuaryClient, JanuaryTokenProviderError, type JanuaryClientTokenResponse, } from '@januaryai/web-sdk'; async function fetchJanuaryToken(): Promise { const response = await fetch('/api/january-token', { method: 'GET', credentials: 'include', headers: { Accept: 'application/json' }, }); if (!response.ok) { throw new JanuaryTokenProviderError( `Token endpoint returned HTTP ${response.status}`, { retryable: response.status === 408 || response.status === 429 || response.status >= 500 }, ); } return response.json() as Promise; } export const january = new JanuaryClient({ clientTokenProvider: fetchJanuaryToken, }); ``` -------------------------------- ### Predict glucose levels using the user client Source: https://docs.january.ai/web-sdk/guides/glucose-prediction.md Uses the user client to request a glucose prediction based on profile data, food selections, and a start time. ```ts const prediction = await user.glucose.predict({ userProfile: { age: 35, sex: Sex.male, height: { value: 70, unit: HeightUnit.inches }, weight: { value: 175, unit: WeightUnit.pounds }, activityLevel: ActivityLevel.moderatelyActive, healthConditions: [], }, foods: [portion.selection], startTime: new Date(), }); ``` -------------------------------- ### Initialize JanuaryClient Source: https://docs.january.ai/web-sdk/reference/client-and-resources.md Constructor signatures for JanuaryClient supporting either direct access tokens or provider-managed token refresh. ```ts new JanuaryClient( | { accessToken: string; fetch?: typeof globalThis.fetch } | { clientTokenProvider: JanuaryTokenProvider | JanuaryTokenProviderCallback; tokenRetryPolicy?: JanuaryTokenRetryPolicy; fetch?: typeof globalThis.fetch; } ) interface JanuaryTokenProvider { fetchClientToken(): Promise; } type JanuaryTokenProviderCallback = () => Promise; type JanuaryClientTokenResponse = | { token: string; expiresIn: number } | { token: string; expires_in: number }; ``` -------------------------------- ### Initialize JanuaryClient Source: https://docs.january.ai/ios-sdk/reference/authentication-api.md Provides multiple initializers for the JanuaryClient, supporting token providers, static tokens, or development API keys. ```swift public struct JanuaryClient: Sendable { public let foods: FoodsResource public let restaurants: RestaurantsResource public let foodAnalysis: FoodAnalysisResource public let foodLogs: FoodLogsResource public let glucose: GlucoseResource public init( endUserID: String, timezone: TimeZone? = nil, clientTokenProvider: @escaping JanuaryClientTokenProvider, tokenRetryPolicy: JanuaryTokenRetryPolicy = .default ) throws public init( endUserID: String, timezone: TimeZone? = nil, clientTokenProvider: any JanuaryTokenProvider, tokenRetryPolicy: JanuaryTokenRetryPolicy = .default ) throws public init( clientToken: String, endUserID: String, timezone: TimeZone? = nil ) throws public init( developmentAPIKey: String, endUserID: String, timezone: TimeZone? = nil ) throws } ``` -------------------------------- ### Manage Food Logs with Scoped Client Source: https://docs.january.ai/android-sdk/guides/food-logs.md Demonstrates creating, listing, retrieving, updating, and deleting food logs using a user-scoped client instance. ```kotlin val user = client.forUser( PartnerUserId(account.id), timezone = "America/New_York", ) val log = user.foodLogs.create( foods = listOf(portion.selection), timestampUtc = Instant.now().toString(), name = "Breakfast", ) val logs = user.foodLogs.list("2026-08-01", "2026-08-31") val logId = requireNotNull(log.id) { "January did not return a Food Log ID." } val savedLog = user.foodLogs.get(logId) user.foodLogs.update(requireNotNull(savedLog.id), name = "Post-workout breakfast") user.foodLogs.delete(requireNotNull(savedLog.id)) ``` -------------------------------- ### Initialize JanuaryPartnerUserClient Source: https://docs.january.ai/android-sdk/reference/client-and-resources.md Methods to create a user-scoped client for performing operations within a specific user context. ```kotlin fun forUser(context: PartnerUserContext): JanuaryPartnerUserClient fun forUser( endUserId: PartnerUserId, timezone: String? = null, ): JanuaryPartnerUserClient ``` -------------------------------- ### Import JanuaryClient Source: https://docs.january.ai/web-sdk/getting-started/installation.md Import the client class to begin interacting with the SDK. ```ts import { JanuaryClient } from '@januaryai/web-sdk'; ``` -------------------------------- ### Visualize the SDK security model Source: https://docs.january.ai/web-sdk/overview.md Illustrates the flow of authentication tokens between the browser, partner backend, and January services. ```text Browser ── authenticated request ──▶ Partner backend ── private exchange ──▶ January Browser ◀────── { token, expiresIn } ────────────────────────────────────┘ Browser ───── Authorization: Bearer ct-… ─────────────────────────────▶ January ``` -------------------------------- ### Initialize January Client and Search Foods Source: https://docs.january.ai/web-sdk/getting-started/quick-start.md Defines the token provider and client initialization, followed by a function to search for food items. ```ts import { JanuaryError, JanuaryClient, JanuaryTokenProviderError, type JanuaryClientTokenResponse, } from '@januaryai/web-sdk'; const endUserId = 'replace-with-your-stable-user-id'; async function fetchJanuaryToken(): Promise { let response: Response; try { response = await fetch('/api/january-token', { method: 'GET', // The server must also return Cache-Control: no-store. cache: 'no-store', credentials: 'include', headers: { Accept: 'application/json', }, }); } catch (error) { throw new JanuaryTokenProviderError( 'Token endpoint is unavailable', { retryable: true, cause: error }, ); } if (!response.ok) { throw new JanuaryTokenProviderError( `Token endpoint returned HTTP ${response.status}`, { retryable: response.status === 408 || response.status === 429 || response.status >= 500 }, ); } return (await response.json()) as JanuaryClientTokenResponse; } const january = new JanuaryClient({ clientTokenProvider: fetchJanuaryToken, }); const user = january.forUser( endUserId, Intl.DateTimeFormat().resolvedOptions().timeZone, ); export async function renderJanuaryQuickStart(output: HTMLElement) { try { const response = await user.foods.search({ query: 'greek yogurt', limit: 5, }); output.style.whiteSpace = 'pre-line'; output.textContent = response.items.map((food) => food.name).join('\n'); } catch (error) { if (error instanceof JanuaryError) { console.error('January request failed', { category: error.category, status: error.status, code: error.code, requestId: error.requestId, message: error.message, }); } else { console.error('Integration failed:', error); } throw error; } } ``` -------------------------------- ### Resource Methods Overview Source: https://docs.january.ai/ios-sdk/reference/client-and-resources.md A summary of available resource methods in the January AI iOS SDK. All methods are async throws and utilize the configured PartnerUserContext automatically. ```APIDOC ## Resource Methods ### Foods - `foods.search(_:)`: Search foods by name - `foods.autocomplete(_:)`: Return type-ahead suggestions - `foods.get(id:endUserID:)`: Hydrate a food with all servings - `foods.lookupBarcode(_:)`: Look up UPC/EAN/GTIN codes - `foods.suggestAlternatives(_:)`: Find dietary alternatives ### Restaurants - `restaurants.search(_:)`: Find nearby restaurants - `restaurants.searchMenuItems(_:)`: Find nearby menu items - `restaurants.getMenuItems(_:)`: Load a restaurant's menu by its search-result ID ### Food Analysis - `foodAnalysis.analyzePhoto(_:)`: Analyze a food image - `foodAnalysis.analyzeDescription(_:)`: Analyze a meal description - `foodAnalysis.correct(_:)`: Correct a scan with text feedback ### Food Logs - `foodLogs.create(_:)`: Create a food log - `foodLogs.list(_:)`: List food logs for a date range - `foodLogs.get(_:)`: Get one food log by ID - `foodLogs.update(_:)`: Update a food log - `foodLogs.delete(_:)`: Delete a food log ### Glucose - `glucose.predict(_:)`: Predict glucose impact ``` -------------------------------- ### JanuaryPartnerClient Initialization Source: https://docs.january.ai/android-sdk/reference/client-and-resources.md Methods to initialize the JanuaryPartnerClient using either a fixed token or a token provider. ```APIDOC ## JanuaryPartnerClient.withClientToken ### Description Initializes the client with a fixed short-lived token. ### Signature `JanuaryPartnerClient.withClientToken(clientToken: String): JanuaryPartnerClient` ## JanuaryPartnerClient.withClientTokenProvider ### Description Initializes the client with a token provider for app-managed token refreshing. ### Signature `JanuaryPartnerClient.withClientTokenProvider(provider: JanuaryTokenProvider, tokenRetryPolicy: JanuaryTokenRetryPolicy = JanuaryTokenRetryPolicy()): JanuaryPartnerClient` ``` -------------------------------- ### JanuaryClient Initialization Source: https://docs.january.ai/ios-sdk/reference/authentication-api.md Initializes the JanuaryClient using various authentication methods including token providers or development API keys. ```APIDOC ## init(endUserID:timezone:clientTokenProvider:tokenRetryPolicy:) ### Description Initializes a client using a closure-based token provider for production environments. ### Parameters - **endUserID** (String) - Required - The unique identifier for the end user. - **timezone** (TimeZone?) - Optional - The user's timezone. - **clientTokenProvider** (@escaping JanuaryClientTokenProvider) - Required - An async closure that fetches a client token. - **tokenRetryPolicy** (JanuaryTokenRetryPolicy) - Optional - The retry policy for token fetching. ## init(developmentAPIKey:endUserID:timezone:) ### Description Initializes a client for local Debug testing using an API key. This is rejected at compile time in release builds. ### Parameters - **developmentAPIKey** (String) - Required - The API key for development. - **endUserID** (String) - Required - The unique identifier for the end user. - **timezone** (TimeZone?) - Optional - The user's timezone. ``` -------------------------------- ### Initialize JanuaryClient with a fixed token Source: https://docs.january.ai/web-sdk/getting-started/authentication.md Use this method when the host application manages token refresh and client recreation manually. ```ts const january = new JanuaryClient({ accessToken: clientToken }); ``` -------------------------------- ### Run live integration tests Source: https://docs.january.ai/ios-sdk/reference/testing.md Executes the live integration test against a configured token endpoint by providing necessary environment variables. ```sh PARTNER_TOKEN_URL=https://your-backend.example.com/january-token \ PARTNER_APP_SESSION_TOKEN=your-app-session-token \ JANUARY_END_USER_ID=your-test-user \ node scripts/check-coverage.mjs ``` -------------------------------- ### Configure server-side environment variables Source: https://docs.january.ai/web-sdk/getting-started/example-app.md Set these variables for production-shaped token flow. Ensure credentials remain server-side and are not exposed to the browser. ```text PARTNER_TOKEN_URL=http://localhost:8787/january-token PARTNER_APP_SESSION_TOKEN=your-local-app-session-or-relay-secret JANUARY_END_USER_ID=your-test-user ``` -------------------------------- ### Manage Food Logs with January Web SDK Source: https://docs.january.ai/web-sdk/guides/food-logs.md Demonstrates the lifecycle of food logs including creation, listing, retrieval, updates, and deletion using a scoped user client. ```ts const user = january.forUser({ endUserId: authenticatedAccount.id, endUserTimezone: authenticatedAccount.timezone, }); const log = await user.foodLogs.create({ foods: [portion.selection], timestampUtc: new Date().toISOString(), name: 'Breakfast', }); await user.foodLogs.list({ start: '2026-08-01', end: '2026-08-31' }); if (!log.id) throw new Error('January did not return a Food Log ID.'); const savedLog = await user.foodLogs.get({ logId: log.id }); await user.foodLogs.update({ logId: savedLog.id ?? log.id, name: 'Post-workout breakfast' }); await user.foodLogs.delete({ logId: savedLog.id ?? log.id }); ``` -------------------------------- ### Initialize JanuaryPartnerClient with Fixed Token Source: https://docs.january.ai/android-sdk/getting-started/authentication.md Pass a current client token directly when the host application manages token refresh and client recreation. ```kotlin val january = JanuaryPartnerClient.withClientToken(clientToken) ``` -------------------------------- ### Perform Food Search and Portion Creation in Kotlin Source: https://docs.january.ai/android-sdk/concepts/food-lifecycle.md Demonstrates the sequence of searching for a food item, retrieving its details, and creating a scaled FoodPortion. Handle empty serving lists and potential FoodPortionException errors. ```kotlin import ai.january.partner.foods.GetFoodRequest import ai.january.partner.foods.SearchFoodsRequest import ai.january.partner.foods.portion val results = january.foods.search(SearchFoodsRequest(query = "banana")) val selected = results.items.first() val food = january.foods.get(GetFoodRequest(foodId = selected.id)) val serving = food.servings.firstOrNull { it.isPrimary } ?: food.servings.first() val portion = food.portion(servingId = serving.id, quantity = 1.5) println(portion.nutrition.calories?.value) val apiSelection = portion.selection ``` -------------------------------- ### Configure VS Code for MCP Source: https://docs.january.ai/docs/mcp-server.md Add the January server to the .vscode/mcp.json configuration file. ```json { "servers": { "january": { "type": "http", "url": "https://mcp.january.ai/mcp", "headers": { "Authorization": "Bearer sk-your-key" } } } } ``` -------------------------------- ### JanuaryClient Configuration Source: https://docs.january.ai/web-sdk/reference/retries-and-lifecycle.md Configuring the JanuaryClient with a custom token provider and retry policy settings. ```APIDOC ## JanuaryClient Configuration ### Description Initializes the client with a token provider and a custom retry policy for token fetching operations. ### Parameters - **clientTokenProvider** (function) - Required - A function that fetches the client token. - **tokenRetryPolicy** (object) - Optional - Configuration for retry behavior: - **maximumAttempts** (number) - Total retry attempts. - **initialDelayMs** (number) - Initial delay in milliseconds. - **multiplier** (number) - Delay multiplier. - **maximumDelayMs** (number) - Maximum delay in milliseconds. - **jitterRatio** (number) - Jitter ratio for randomized delays. ``` -------------------------------- ### Connect Claude Code to MCP Source: https://docs.january.ai/docs/mcp-server.md Register the January server and execute a prompt using Claude Code. ```bash claude mcp add --scope user --transport http january https://mcp.january.ai/mcp \ --header 'Authorization: Bearer sk-your-key' claude -p "Search the January food database for greek yogurt and list the top three matches." --allowedTools mcp__january ``` -------------------------------- ### Search and Create FoodPortion Source: https://docs.january.ai/web-sdk/concepts/food-lifecycle.md Demonstrates the workflow from searching for a food item to creating a FoodPortion instance with a specific serving and quantity. ```ts import { FoodPortion } from '@januaryai/web-sdk'; const results = await january.foods.search({ query: 'banana' }); const selected = results.items[0]; if (!selected) throw new Error('No matching food'); const food = await january.foods.get({ foodId: selected.id }); const serving = food.servings.find((item) => item.isPrimary) ?? food.servings[0]; if (!serving) throw new Error('Food has no serving options'); const portion = FoodPortion.from(food, { servingId: serving.id, quantity: 1.5, }); console.log(portion.nutrition.calories?.value); const apiSelection = portion.selection; ``` -------------------------------- ### Initialize height and weight units Source: https://docs.january.ai/ios-sdk/reference/validation.md Use these types to define physical measurements with explicit units for glucose profiles. ```swift let height = Height(value: 178, unit: .centimeters) let weight = Weight(value: 80, unit: .kilograms) ``` -------------------------------- ### Create User-Scoped Client Source: https://docs.january.ai/web-sdk/reference/client-and-resources.md Methods to instantiate a JanuaryPartnerUserClient for specific user contexts. ```ts forUser(context: PartnerUserContext): JanuaryPartnerUserClient forUser(endUserId: string, endUserTimezone?: string): JanuaryPartnerUserClient ``` -------------------------------- ### Configure local.properties for Token Mode Source: https://docs.january.ai/android-sdk/getting-started/example-app.md Add these properties to local.properties to authenticate the demo app. Ensure the partner token URL is reachable from the device or emulator. ```properties january.partnerTokenUrl=http://10.0.2.2:8787/january-token january.partnerSessionToken=your-local-app-session-or-relay-secret ``` -------------------------------- ### Perform API operations Source: https://docs.january.ai/ios-sdk/getting-started/authentication.md Once the client is configured, resources like food search are accessible directly. ```swift let results = try await client.foods.search(.init(query: "greek yogurt")) ``` -------------------------------- ### Configure local development token provider Source: https://docs.january.ai/ios-sdk/getting-started/authentication.md Uses JanuaryDevelopmentTokenProvider for local debugging. This must be wrapped in a DEBUG check and never used in production builds. ```swift #if DEBUG guard let apiKey = ProcessInfo.processInfo.environment["JANUARY_API_KEY"], let rawUserID = ProcessInfo.processInfo.environment["JANUARY_END_USER_ID"] else { fatalError("Set the local January development credentials in the Xcode scheme.") } let provider = try JanuaryDevelopmentTokenProvider(apiKey: apiKey) let client = try JanuaryClient( endUserID: rawUserID, clientTokenProvider: provider ) #endif ``` -------------------------------- ### preparePhotoScanImage(image, options, adapter) Source: https://docs.january.ai/web-sdk/reference/discovery-and-scanning-api.md Prepares a Blob image for scanning by resizing and adjusting quality. ```APIDOC ## preparePhotoScanImage(image, options, adapter) ### Description Prepares a Blob image for scanning by resizing and adjusting quality. ### Parameters - **image** (Blob) - Required - The image file to process. - **options** (object) - Optional - Configuration for 'maxDimension' (default 1000) and 'jpegQuality' (default 0.7). ``` -------------------------------- ### Initialize with app-managed fixed token Source: https://docs.january.ai/ios-sdk/getting-started/authentication.md Creates a client instance using a static token. Note that the SDK cannot refresh this client when the token expires. ```swift let client = try JanuaryClient( clientToken: clientTokenValue, endUserID: endUserID ) ``` -------------------------------- ### Run instrumentation tests on device or emulator Source: https://docs.january.ai/android-sdk/reference/testing-and-support.md Execute these commands to verify camera and Android-runtime coverage on a connected device or emulator. ```bash ./gradlew :sdk:connectedDebugAndroidTest ./gradlew :demo:connectedDebugAndroidTest ``` -------------------------------- ### Configure Run environment variables Source: https://docs.january.ai/ios-sdk/getting-started/quick-start.md Set these variables in the Xcode scheme to provide the SDK with the necessary backend endpoint and user credentials. ```text PARTNER_TOKEN_URL=https://your-backend.example.com/january-token PARTNER_APP_SESSION_TOKEN=your-app-session-token JANUARY_END_USER_ID=your-stable-user-id ``` -------------------------------- ### Configure app/build.gradle.kts Source: https://docs.january.ai/android-sdk/getting-started/quick-start.md Defines the necessary plugins, build configuration fields for authentication, and SDK dependencies for the Android module. ```kotlin plugins { id("com.android.application") } val januaryTokenUrl = providers.gradleProperty("januaryTokenUrl").orNull ?: "" val partnerSessionToken = providers.gradleProperty("partnerSessionToken").orNull ?: "" val januaryEndUserId = providers.gradleProperty("januaryEndUserId").orNull ?: "" android { namespace = "com.example.januaryquickstart" compileSdk = 36 defaultConfig { applicationId = "com.example.januaryquickstart" minSdk = 26 targetSdk = 36 versionCode = 1 versionName = "1.0" buildConfigField("String", "JANUARY_TOKEN_URL", "\"$januaryTokenUrl\"") buildConfigField("String", "PARTNER_SESSION_TOKEN", "\"$partnerSessionToken\"") buildConfigField("String", "JANUARY_END_USER_ID", "\"$januaryEndUserId\"") } buildFeatures { buildConfig = true } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } } dependencies { implementation("ai.january:january-sdk-android:0.1.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") } ``` -------------------------------- ### create(request) Source: https://docs.january.ai/web-sdk/reference/user-resources-api.md Creates a new food log entry. ```APIDOC ## create(request) ### Description Creates a new food log entry for the user. ### Parameters - **foods** (FoodSelection[]) - Required - List of foods to log. - **timestampUtc** (string) - Optional - ISO-8601 timestamp. - **name** (string) - Optional - Name of the log. - **signal** (AbortSignal) - Optional - AbortSignal for request cancellation. ### Response - **FoodLog** (Object) - The created food log object. ``` -------------------------------- ### Verify dependency resolution Source: https://docs.january.ai/android-sdk/getting-started/installation.md Run Gradle tasks to confirm the SDK dependency is correctly mapped to the local project. ```bash ./gradlew :app:dependencies --configuration debugRuntimeClasspath ./gradlew :app:assembleDebug ``` -------------------------------- ### Implement JanuaryTokenProvider in Kotlin Source: https://docs.january.ai/android-sdk/getting-started/authentication.md Use this provider to fetch client tokens from your own authenticated backend using platform networking. ```kotlin import ai.january.partner.JanuaryClientToken import ai.january.partner.JanuaryTokenProvider import ai.january.partner.JanuaryTokenProviderException import java.net.HttpURLConnection import java.net.URL import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext class PartnerBackendTokenProvider( endpoint: String, private val sessionToken: suspend () -> String, ) : JanuaryTokenProvider { private val endpointUrl = URL(endpoint) override suspend fun fetchClientToken(): JanuaryClientToken = withContext(Dispatchers.IO) { val connection = (endpointUrl.openConnection() as HttpURLConnection).apply { requestMethod = "GET" connectTimeout = 10_000 readTimeout = 10_000 setRequestProperty("Accept", "application/json") setRequestProperty("Authorization", "Bearer ${sessionToken()}") } try { val status = connection.responseCode if (status !in 200..299) { throw JanuaryTokenProviderException( message = "Token endpoint returned HTTP $status", retryable = status == 408 || status == 429 || status >= 500, ) } val json = connection.inputStream.bufferedReader().use { it.readText() } JanuaryClientToken.fromJson(json) } finally { connection.disconnect() } } } ``` -------------------------------- ### Configured Client Food Log Operations Source: https://docs.january.ai/ios-sdk/reference/food-logs-api.md Simplified methods available on JanuaryClient.foodLogs that automatically utilize the client's configured context. ```swift public func create( foods: [FoodSelection], timestampUTC: String? = nil, name: String? = nil ) async throws -> FoodLog public func list(start: String, end: String) async throws -> ListFoodLogsResponse public func get(id: String) async throws -> FoodLog public func update( id: String, foods: [FoodSelection]? = nil, timestampUTC: String? = nil, name: String? = nil ) async throws -> FoodLog public func delete(id: String) async throws -> DeleteFoodLogResponse ``` -------------------------------- ### Implement ContentView.swift Source: https://docs.january.ai/ios-sdk/getting-started/quick-start.md Contains the token provider logic, view model for data fetching, and the main view structure. ```swift import Foundation import January import SwiftUI enum QuickstartError: LocalizedError { case missingEnvironment(String) case invalidURL(String) case invalidResponse case tokenRequestFailed(Int) case noFoods var errorDescription: String? { switch self { case .missingEnvironment(let name): return "Set \(name) in the Xcode scheme." case .invalidURL(let value): return "Invalid partner token URL: \(value)" case .invalidResponse: return "The partner token endpoint returned an invalid response." case .tokenRequestFailed(let status): return "The partner token endpoint returned HTTP \(status)." case .noFoods: return "January returned no matching foods." } } } struct PartnerBackendTokenProvider: JanuaryTokenProvider { let endpoint: URL let appSessionToken: String func fetchClientToken(for endUserID: String) async throws -> JanuaryClientToken { // This calls your server to mint a new January client token. var request = URLRequest(endpoint) request.httpMethod = "POST" request.setValue( "Bearer \(appSessionToken)", forHTTPHeaderField: "Authorization" ) request.setValue(endUserID, forHTTPHeaderField: "x-end-user-id") let data: Data let response: URLResponse do { (data, response) = try await URLSession.shared.data(for: request) } catch is CancellationError { throw CancellationError() } catch { throw JanuaryTokenProviderError( "The partner token endpoint is unavailable.", retryable: true ) } guard let http = response as? HTTPURLResponse else { throw QuickstartError.invalidResponse } guard (200..<300).contains(http.statusCode) else { if http.statusCode == 408 || http.statusCode == 429 || http.statusCode >= 500 { throw JanuaryTokenProviderError( "The partner token endpoint is temporarily unavailable.", retryable: true ) } throw QuickstartError.tokenRequestFailed(http.statusCode) } return try JSONDecoder().decode(JanuaryClientToken.self, from: data) } } @MainActor final class QuickstartViewModel: ObservableObject { enum State { case loading case loaded(name: String, servings: Int, calories: Double) case failed(String) } @Published private(set) var state: State = .loading func load() async { state = .loading do { let environment = ProcessInfo.processInfo.environment guard let rawURL = environment["PARTNER_TOKEN_URL"] else { throw QuickstartError.missingEnvironment("PARTNER_TOKEN_URL") } guard let endpoint = URL(string: rawURL) else { throw QuickstartError.invalidURL(rawURL) } guard let appSessionToken = environment["PARTNER_APP_SESSION_TOKEN"] else { throw QuickstartError.missingEnvironment("PARTNER_APP_SESSION_TOKEN") } guard let endUserID = environment["JANUARY_END_USER_ID"] else { throw QuickstartError.missingEnvironment("JANUARY_END_USER_ID") } let provider = PartnerBackendTokenProvider( endpoint: endpoint, appSessionToken: appSessionToken ) let january = try JanuaryClient( endUserID: endUserID, clientTokenProvider: provider ) let results = try await january.foods.search( .init(query: "greek yogurt", category: .branded, limit: 10) ) guard let match = results.items.first else { throw QuickstartError.noFoods } let food = try await january.foods.get(id: match.id) let portion = try food.portion(quantity: 1) state = .loaded( name: food.name, servings: food.servings.count, calories: portion.nutrition.calories?.value ?? 0 ) } catch is CancellationError { return } catch { state = .failed(error.localizedDescription) } } } struct ContentView: View { @StateObject private var model = QuickstartViewModel() var body: some View { VStack(spacing: 16) { Text("January SDK") .font(.title.bold()) ```