peqaboo.ready(): Promise<void>Resolves once the native bridge has handshaked. Always await before calling other APIs.
Returns
Promise<void>await peqaboo.ready();
console.log('Bridge ready, version', peqaboo.bridgeVersion);SDK Reference
Every method below is available on the auto-injected peqaboo global. No import, no install. Always await peqaboo.ready() before calling anything else.
/// <reference types="@decennium/booapp-sdk" />
// peqaboo is auto-injected — no import line needed.Bridge readiness, environment detection, and runtime metadata. Always call ready() before anything else.
peqaboo.ready(): Promise<void>Resolves once the native bridge has handshaked. Always await before calling other APIs.
Returns
Promise<void>await peqaboo.ready();
console.log('Bridge ready, version', peqaboo.bridgeVersion);peqaboo.isInApp: booleantrue when running inside the Peqaboo WebView; false in a plain browser. Use to conditionally fall back.
Returns
booleanif (!peqaboo.isInApp) {
document.body.innerHTML = 'Open in Peqaboo to use this app.';
return;
}peqaboo.platform: 'ios' | 'android' | 'web'Host platform reported by the bridge.
Returns
'ios' | 'android' | 'web'if (peqaboo.platform === 'ios') { /* iOS-specific tweak */ }peqaboo.bridgeVersion: numberNative bridge version. v3 supports permission scopes; v2 is legacy.
Returns
numberif (peqaboo.bridgeVersion < 3) {
alert('Please update Peqaboo to use this BooApp.');
}peqaboo.lang: stringBCP-47 language tag of the user (e.g. zh-HK, en-US).
Returns
stringconst isChinese = peqaboo.lang.startsWith('zh');peqaboo.uid: string | nullCurrent logged-in user id, or null if not logged in. Use requireLogin() to force login.
Returns
string | nullif (!peqaboo.uid) await peqaboo.requireLogin();User identity. Login is handled by Peqaboo — your BooApp just asks who the user is.
peqaboo.requireLogin(): Promise<User>Returns the current user. If no user is logged in, opens the native login flow first. Resolves with the User object after success.
scope: auth.requireLogin
Returns
Promise<User>const user = await peqaboo.requireLogin();
console.log(user.uid, user.name, user.avatarUrl);Pet records the user has added in Peqaboo. Read-only by default; update requires explicit user grant.
peqaboo.pet.list(): Promise<Pet[]>List all pets owned by the current user.
scope: pet.list
Returns
Promise<Pet[]>const pets = await peqaboo.pet.list();
pets.forEach(p => console.log(p.name, p.species));peqaboo.pet.read(petId: string): Promise<Pet>Read a single pet by id. Includes full profile, breed, birth date, photo URLs.
scope: pet.read
Parameters
petId string — The petId from pet.list().Returns
Promise<Pet>const pet = await peqaboo.pet.read('pet_abc123');
console.log(pet.weight, pet.allergies);peqaboo.pet.update(petId, patch): Promise<Pet>Update fields on a pet. The user is shown a confirm sheet before any write.
scope: pet.update
Parameters
petId string — Target pet id.patch Partial<Pet> — Fields to update.Returns
Promise<Pet>await peqaboo.pet.update('pet_abc123', { weight: 5.4 });Pick or capture images and videos. Returns native File objects you can upload via storage.upload.
peqaboo.media.pickImage(opts?): Promise<File>Open the native image picker. Set opts.source = 'camera' to skip directly to camera.
scope: media.pickImage
Parameters
opts.source 'camera' | 'library' — Default is library.opts.maxSize number — Max edge length in px before downscale.Returns
Promise<File>const file = await peqaboo.media.pickImage({ source: 'camera' });
const url = await peqaboo.storage.upload(file);peqaboo.media.pickVideo(opts?): Promise<File>Pick or capture a video.
scope: media.pickVideo
Returns
Promise<File>const video = await peqaboo.media.pickVideo({ maxDuration: 30 });peqaboo.media.takePhoto(): Promise<File>Open the native camera directly, skipping the chooser.
scope: media.takePhoto
Returns
Promise<File>const photo = await peqaboo.media.takePhoto();Upload files to Peqaboo Cloud Storage. Returns a public CDN URL you can render or save.
peqaboo.storage.upload(file, opts?): Promise<string>Upload a file. Files are scoped to your BooApp and the current user; other apps cannot read them.
scope: storage.upload
Parameters
file File — A File from media.* or a blob.opts.path string — Optional sub-path within your app scope.Returns
Promise<string>const file = await peqaboo.media.pickImage();
const url = await peqaboo.storage.upload(file, { path: 'cards/' });
img.src = url;Read the user's location. One-shot or subscription.
peqaboo.location.getCurrent(): Promise<Coords>Returns one geolocation reading. Triggers a native permission prompt the first time.
scope: location.getCurrent
Returns
Promise<{ lat: number; lng: number; accuracy: number }>const { lat, lng } = await peqaboo.location.getCurrent();peqaboo.location.subscribe(cb): () => voidSubscribe to position updates. Returns an unsubscribe function.
scope: location.subscribe
Returns
() => voidconst unsub = peqaboo.location.subscribe(coords => {
console.log(coords.lat, coords.lng);
});
// later
unsub();Charge the user. Always shows a native confirm sheet — high-tier scope, never silent.
peqaboo.payment.request(opts): Promise<PaymentResult>Request a payment. The user sees a native modal with full breakdown and must tap Confirm.
scope: payment.request
Parameters
opts.amount number — Amount in minor units (e.g. cents).opts.currency string — ISO 4217, e.g. HKD, USD.opts.description string — What the user is paying for.Returns
Promise<{ paymentId: string; status: 'success' | 'cancelled' }>const r = await peqaboo.payment.request({
amount: 4800, currency: 'HKD',
description: 'Loyalty card stamp set'
});
if (r.status === 'success') unlockReward();Send push to the current user (e.g. reminders for the BooApp).
peqaboo.notification.send(opts): Promise<void>Schedule a push for the current user. Useful for reminders, follow-ups, drip flows.
scope: notification.send
Parameters
opts.title string — Notification title.opts.body string — Notification body.opts.scheduleAt number — Unix ms timestamp. Omit to send now.opts.deeplink string — Optional path inside your BooApp to open on tap.Returns
Promise<void>await peqaboo.notification.send({
title: 'Daily walk',
body: 'Time to walk Mochi!',
scheduleAt: Date.now() + 8 * 3600 * 1000,
});Open a chat with another Peqaboo user.
peqaboo.chat.openWith(uid, opts?): Promise<void>Open the native chat sheet. You can prefill a starter message for the user to send.
scope: chat.openWith
Parameters
uid string — Target user id.opts.prefill string — Optional draft text to seed the input.Returns
Promise<void>await peqaboo.chat.openWith('user_xyz', {
prefill: 'Hi! I saw your post about the puppy class…'
});Native device features — share sheet, haptics, QR scanner.
peqaboo.device.share(opts): Promise<void>Open the native share sheet.
scope: device.share
Parameters
opts.title string — Share title.opts.text string — Body text.opts.url string — Optional URL to share.Returns
Promise<void>await peqaboo.device.share({
title: 'Mochi got a new card!',
url: 'https://peqaboo.app/cards/abc',
});peqaboo.device.haptic(type): voidTrigger a haptic tap. Sync — no await needed.
scope: device.haptic
Parameters
type 'light' | 'medium' | 'heavy' — Intensity.Returns
voidpeqaboo.device.haptic('light');peqaboo.device.scanCode(): Promise<string>Open the native QR scanner. Resolves with the decoded payload.
scope: device.scanCode
Returns
Promise<string>const code = await peqaboo.device.scanCode();
console.log('Scanned:', code);Per-user key/value store. Scoped to your BooApp + the current user. Persists across sessions.
peqaboo.data.set(key, value): Promise<{ key, value }>Set/replace a value. Max 100 KB serialised.
scope: data.write
Returns
Promise<{ key, value }>await peqaboo.data.set('streakCount', 7);peqaboo.data.get(key): Promise<{ key, value, exists }>Read a value. Returns null when missing.
scope: data.read
Returns
Promise<{ key, value, exists }>const { value } = await peqaboo.data.get('streakCount');peqaboo.data.delete(key): Promise<void>Delete a key. No-op if absent.
scope: data.write
Returns
Promise<void>await peqaboo.data.delete('streakCount');peqaboo.data.list(): Promise<{ keys: Array<{ key, _updatedAt }> }>List keys (latest 500).
scope: data.read
Returns
Promise<{ keys: ... }>const { keys } = await peqaboo.data.list();Per-user collections that mirror Firestore — add/set/update/delete/get/list/onChange. Auto _createdAt + _updatedAt timestamps.
peqaboo.collection(name).add(doc): Promise<T & { id }>Append with auto-id. Doc cap: 100 KB, 100 top-level fields.
scope: data.write
Returns
Promise<T & { id }>const visits = peqaboo.collection('visits');
const r = await visits.add({ petId: 'p1', rating: 5 });collection.list(opts?): Promise<{ docs, cursor, hasMore }>Filtered query. If a composite index is missing the call throws QueryNeedsIndexError once — the platform auto-files a deploy ticket; retry in ~5 min.
scope: data.read
Returns
Promise<QueryResult<T>>const page = await visits.list({
where: [['petId', '==', 'p1']],
orderBy: [['_createdAtDate', 'desc']],
limit: 20,
});collection.onChange(cb, opts?): () => void5-second polling fallback (true streaming planned).
scope: data.read
Returns
() => voidconst off = visits.onChange(page => render(page), {
where: [['petId', '==', 'p1']],
});
// later: off();Distribution channels (Phase 9e). Pin THIS BooApp on the caller's public profile so other users see it under the Apps rail when they visit the profile.
peqaboo.profile.pinThisApp(): Promise<{ appId, pinned }>Set `installs/{uid}.pinned = true` for this BooApp. The user's public profile then shows it under the Pinned rail.
scope: profile.pin
Returns
Promise<{ appId: string; pinned: true }>// After delivering value (e.g. user printed their NFC card),
// prompt them to pin so friends can discover it.
await peqaboo.profile.pinThisApp();peqaboo.profile.unpinThisApp(): Promise<{ appId, pinned }>Remove this BooApp from the user’s pinned rail.
scope: profile.pin
Returns
Promise<{ appId: string; pinned: false }>await peqaboo.profile.unpinThisApp();Subscribe to native events pushed by the platform — lifecycle, push, NFC, keyboard.
peqaboo.on(event, cb): () => voidSubscribe to a Bridge Event. Returns an unsubscribe function. Known events: appResume, appPause, authTokenRefreshed, pushReceived, nfcTagDetected, keyboardShow, keyboardHide.
Returns
() => voidconst off = peqaboo.on('appResume', () => {
refreshData();
});
// later
off();Read the user's friends and recent chat partners — useful for picking a recipient, sharing inside the user's social graph, or showing a recent-activity rail. Reuses the existing Peqaboo friend + chat APIs.
peqaboo.contacts.list(opts?): Promise<{ contacts: ContactRow[] }>List the user's friends + recent chat partners. opts.source = 'friends' | 'chat' | 'all' (default 'all').
scope: contacts.read
Returns
Promise<{ contacts: ContactRow[] }>const { contacts } = await peqaboo.contacts.list({ source: 'friends' });peqaboo.contacts.pick(): Promise<ContactRow | null>Show a native bottom-sheet contact picker (Friends / Recent tabs). Resolves with the picked row or null on cancel.
scope: contacts.read
Returns
Promise<ContactRow | null>const c = await peqaboo.contacts.pick();
if (c) await peqaboo.chat.openWith(c.uid);Add reminders into the user's existing pet reminders. Tagged with this BooApp's id so the BooApp can list and delete only the reminders it created. Rate limit: 10 writes / day / user.
peqaboo.reminder.add(data): Promise<Reminder>Add a reminder. Body: { petId, title, dueAt (ISO), repeat?, notes? }. Writes to the petReminders collection scoped with sourceBooAppId.
scope: reminder.write
Returns
Promise<Reminder>await peqaboo.reminder.add({
petId: 'p1',
title: 'Walk Mochi',
dueAt: new Date(Date.now() + 3600_000).toISOString(),
});peqaboo.reminder.list(): Promise<{ reminders: Reminder[] }>List reminders this BooApp created (others are hidden).
scope: reminder.write
Returns
Promise<{ reminders: Reminder[] }>const { reminders } = await peqaboo.reminder.list();peqaboo.reminder.delete(reminderId): Promise<void>Delete a reminder. Only succeeds if the reminder was created by this BooApp.
scope: reminder.write
Returns
Promise<void>await peqaboo.reminder.delete(r.reminderId);Add pet records (vaccine, vet visit, weight log, …) into the user's existing petRecords timeline. Confirms every call (high tier) because pet records are medical-adjacent. Rate limit: 20 writes / day / user.
peqaboo.record.add(data): Promise<Record>Add a pet record. Body: { petId, type, occurredAt (ISO), notes?, attachments? }. Writes to petRecords with sourceBooAppId.
scope: record.write
Returns
Promise<Record>await peqaboo.record.add({
petId: 'p1',
type: 'vaccine',
occurredAt: new Date().toISOString(),
notes: 'Annual rabies booster',
});Schedule a push notification to fire at a future time. The platform's cron dispatcher (1 minute granularity) picks up due rows and fires via the existing push system. Rate limit: 5 / day / user.
peqaboo.notification.schedule(opts): Promise<{ pushId, when, title }>Schedule a push. Body: { when (ISO, future), title, body, link?, imageUrl?, actions? }.
scope: notification.schedule
Returns
Promise<{ pushId: string; when: string; title: string }>await peqaboo.notification.schedule({
when: new Date(Date.now() + 8 * 3600_000).toISOString(),
title: 'Daily walk',
body: 'Time to walk Mochi!',
});Search and read the Peqaboo marketplace product catalog. Filtered to live, sellable products (marketStatus listed | onSale | available). Read-only — purchase still requires payment.request.
peqaboo.market.search(q): Promise<{ hits: ProductHit[]; count; query }>Search products. Returns up to 30 hits.
scope: market.read
Returns
Promise<{ hits: ProductHit[]; count: number; query: string }>const { hits } = await peqaboo.market.search('cat food');peqaboo.market.get(productId): Promise<ProductDetail>Read a single product detail.
scope: market.read
Returns
Promise<ProductDetail>const detail = await peqaboo.market.get(hits[0].productId);