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();Login is handled by Peqaboo. Check the boolean result, then read the current user separately.
peqaboo.requireLogin(): Promise<boolean>Returns true when authenticated. If false, Peqaboo opened the native login screen; resume after login.
scope: auth.requireLogin
Returns
Promise<boolean>const loggedIn = await peqaboo.requireLogin();
if (!loggedIn) return;peqaboo.getUserInfo(): Promise<UserInfo>Read the authenticated user. Fields include uid, userName, userEmail, userProfileImgUrl, lang and regionCode.
Returns
Promise<UserInfo>const user = await peqaboo.getUserInfo();
console.log(user.uid, user.userName, user.userProfileImgUrl);Read pet records the user has added in Peqaboo. Public v3 pet access is read-only.
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.petName, p.petType));peqaboo.pet.read(): Promise<Pet | null>Read the pet currently selected in Peqaboo. To choose by petId, use pet.list() and select the matching row locally.
scope: pet.read
Returns
Promise<Pet | null>const selectedPet = await peqaboo.pet.read();
if (selectedPet) {
console.log(selectedPet.petName, selectedPet.petBreedTranslated, selectedPet.weight);
}Pick or capture images and videos. Returns BooAppFile wrappers accepted by storage.upload.
peqaboo.media.pickImage(opts?): Promise<BooAppFile>Open the native image picker. Camera source uses openCamera and also requires media.takePhoto.
scope: media.pickImage
Parameters
opts.source 'camera' | 'library' — Default is library.opts.maxSize number — Max edge length in px before downscale.Returns
Promise<BooAppFile>const file = await peqaboo.media.pickImage({ source: 'camera' });
const url = await peqaboo.storage.upload(file);peqaboo.media.pickVideo(opts?): Promise<BooAppFile>Pick or capture a video.
scope: media.pickVideo
Returns
Promise<BooAppFile>const video = await peqaboo.media.pickVideo({ maxDuration: 30 });peqaboo.media.takePhoto(): Promise<BooAppFile>Open the native camera directly, skipping the chooser.
scope: media.takePhoto
Returns
Promise<BooAppFile>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 BooAppFile, browser File, or dataUrl object. Plain Blob values are not accepted.
scope: storage.upload
Parameters
file BooAppFile | File | DataUrlFile — A media wrapper, browser File, or object containing dataUrl.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<{ latitude; longitude; accuracy; altitude; speed; timestamp }>const { latitude, longitude } = 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.latitude, coords.longitude, coords.accuracy);
});
// 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 an immediate push to the current user. Use notification.schedule for future delivery.
peqaboo.notification.send(opts): Promise<void>Send an immediate push to the current user.
scope: notification.send
Parameters
opts.title string — Notification title.opts.body string — Notification body.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!',
});Open a chat with another Peqaboo user.
peqaboo.chat.openWith(uid, opts?): Promise<void>Open the native chat sheet, optionally in a Peqaboo business context.
scope: chat.openWith
Parameters
uid string — Target user id.opts.businessId string — Optional Peqaboo business context.Returns
Promise<void>await peqaboo.chat.openWith('user_xyz', {
businessId: 'business_abc'
});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): Promise<boolean>Trigger a haptic tap and await the native result.
scope: device.haptic
Parameters
type 'light' | 'medium' | 'heavy' — Intensity.Returns
Promise<boolean>await peqaboo.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();Native runtime only (the web review preview does not implement profile.*). Pin this BooApp on the caller's public profile so other users see it under the Apps rail.
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);