Skip to main content

fetchContacts

Retrieves the user's contact list in pages. Use size and offset to control pagination, and query.contains for name search. Iterate by calling again with the returned nextOffset until done is true.

Signature

import { fetchContacts } from '@apps-in-toss/web-framework';

declare const fetchContacts: PermissionFunctionWithDialog<
(options: FetchContactsOptions) => Promise<ContactResult>
>;

interface FetchContactsOptions {
/** Number of contacts to fetch per page */
size: number;
/** Start offset. Use 0 on the first call, then pass the returned nextOffset. */
offset: number;
query?: {
/** Filter contacts whose name contains this string */
contains?: string;
};
}

interface ContactEntity {
/** Contact name */
name: string;
/** Phone number (string) */
phoneNumber: string;
}

interface ContactResult {
result: ContactEntity[];
/** Offset to use on the next call. null when no more data. */
nextOffset: number | null;
/** true when all contacts have been fetched. */
done: boolean;
}

Parameters

NameTypeRequiredDescription
options.sizenumberNumber of contacts to retrieve per call. For example, 10 returns up to 10 contacts.
options.offsetnumberStart offset. Pass 0 on the first call, then use nextOffset from the previous response.
options.query.containsstringFilter contacts whose name contains this string. Omit to return all contacts.

Returns

  • Promise<ContactResult> — object containing the contact list and pagination metadata.
    • result — array of contacts, each with name and phoneNumber.
    • nextOffset — offset to use on the next call. null when there are no more contacts.
    • donetrue when all contacts have been fetched.
  • Fails with a permission error if denied. See the "Permission" section.

Permission

Requires the contacts permission. The call fails when the status is explicitly denied — wrap in try/catch. notDetermined lets the call through, but prompting the dialog first is the safer flow. See Guides — Permissions pattern for the full flow.

The callable exposes permission helpers:

const status = await fetchContacts.getPermission();
// 'allowed' | 'denied' | 'notDetermined'

if (status !== 'allowed') {
await fetchContacts.openPermissionDialog();
}

Examples

Minimal

import { fetchContacts } from '@apps-in-toss/web-framework';

async function loadFirstPage() {
const { result, nextOffset, done } = await fetchContacts({ size: 10, offset: 0 });
console.log(result.map((c) => `${c.name}: ${c.phoneNumber}`));
console.log('done:', done, 'nextOffset:', nextOffset);
}

Realistic — paginated contact list with "Load more" button

import { fetchContacts } from '@apps-in-toss/web-framework';
import { useState } from 'react';

interface ContactEntity {
name: string;
phoneNumber: string;
}

export function ContactsList() {
const [contacts, setContacts] = useState<ContactEntity[]>([]);
const [nextOffset, setNextOffset] = useState<number | null>(0);
const [done, setDone] = useState(false);
const [message, setMessage] = useState('');
const [pending, setPending] = useState(false);

async function loadMore() {
if (done || pending) return;
setPending(true);
setMessage('');
try {
const status = await fetchContacts.getPermission();
if (status === 'denied') {
setMessage('Please allow contacts access in Settings.');
return;
}
if (status === 'notDetermined') {
await fetchContacts.openPermissionDialog();
}

const response = await fetchContacts({
size: 20,
offset: nextOffset ?? 0,
});
setContacts((prev) => [...prev, ...response.result]);
setNextOffset(response.nextOffset);
setDone(response.done);
} catch (error) {
setMessage('Could not load contacts. Please try again.');
console.error(error);
} finally {
setPending(false);
}
}

return (
<div>
<ul>
{contacts.map((contact, i) => (
<li key={i}>
{contact.name}{contact.phoneNumber}
</li>
))}
</ul>
{message && <p role="status">{message}</p>}
<button type="button" onClick={loadMore} disabled={done || pending}>
{done ? 'All contacts loaded' : pending ? 'Loading...' : 'Load more'}
</button>
</div>
);
}

Try it live

Run the fetchContacts card on the Contacts page in sdk-example.

Open in sdk-example

External references