Skip to main content

Mobile Integration

Penguin can be integrated into any platform that can make HTTP requests. All raw HTTP calls require two headers:

  • X-AM-API-Key: <your_api_key> — Your developer API key
  • Authorization: Bearer <supabase_anon_key> — The Supabase anon key (see below)

:::info Supabase Anon Key The anon key is a public key that grants anonymous-level access to the API. It is not a secret. The TypeScript SDK includes it automatically. For raw HTTP integrations, use this value:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBlcnV3bmJycWt2bXJsZGhwb29tIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzgyNzg2NzQsImV4cCI6MjA1Mzg1NDY3NH0.kRBiByVkLLazr5bqM-vJtxij-IW4_MIQpcmzz8Niwqw

:::

iOS (Swift)

import Foundation

class PenguinClient {
let apiKey: String
let baseURL = "https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1"
let anonKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBlcnV3bmJycWt2bXJsZGhwb29tIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzgyNzg2NzQsImV4cCI6MjA1Mzg1NDY3NH0.kRBiByVkLLazr5bqM-vJtxij-IW4_MIQpcmzz8Niwqw"

init(apiKey: String) {
self.apiKey = apiKey
}

func search(query: String) async throws -> [String: Any] {
var request = URLRequest(url: URL(string: "\(baseURL)/api-v1/search")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(anonKey)", forHTTPHeaderField: "Authorization")
request.setValue(apiKey, forHTTPHeaderField: "X-AM-API-Key")
request.httpBody = try JSONSerialization.data(withJSONObject: ["query": query])

let (data, _) = try await URLSession.shared.data(for: request)
return try JSONSerialization.jsonObject(with: data) as! [String: Any]
}
}

Android (Kotlin)

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.net.HttpURLConnection
import java.net.URL

class PenguinClient(private val apiKey: String) {
private val baseUrl = "https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1"
private val anonKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

suspend fun search(query: String): String = withContext(Dispatchers.IO) {
val url = URL("$baseUrl/api-v1/search")
val conn = url.openConnection() as HttpURLConnection
conn.requestMethod = "POST"
conn.setRequestProperty("Content-Type", "application/json")
conn.setRequestProperty("Authorization", "Bearer $anonKey")
conn.setRequestProperty("X-AM-API-Key", apiKey)
conn.doOutput = true
conn.outputStream.write("""{"query":"$query"}""".toByteArray())
conn.inputStream.bufferedReader().readText()
}
}

Web (JavaScript)

const ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

async function searchPenguin(query, apiKey) {
const response = await fetch(
'https://peruwnbrqkvmrldhpoom.supabase.co/functions/v1/api-v1/search',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${ANON_KEY}`,
'X-AM-API-Key': apiKey,
},
body: JSON.stringify({ query }),
},
);
return response.json();
}

REST API endpoints

For mobile and non-TypeScript integrations, use the REST API (/api-v1):

EndpointMethodDescription
/api-v1/searchPOSTSearch for capabilities
/api-v1/session/startPOSTStart interactive session
/api-v1/session/messagePOSTSend session message
/api-v1/session/endPOSTEnd session
/api-v1/feedbackPOSTSubmit feedback
/api-v1/openapi.jsonGETOpenAPI 3.1.0 spec

The OpenAPI spec at /api-v1/openapi.json can be imported into tools like Postman or used to generate client code for any language.