> Reverse Contact API documentation. This is the Markdown copy of https://docs.reversecontact.com/sdk/javascript/async-tasks
> Every page is listed at https://docs.reversecontact.com/llms.txt, every endpoint with its credit cost and status at https://docs.reversecontact.com/catalog.json

# Async tasks

> Wait for live profiles, Find Email, Verify Email and Find Phone with the TypeScript SDK, resume saved task ids, and parse webhook deliveries.

- Last verified: 2026-11-04

Live fetches and contact lookups return a `Task` before the result is ready.

## Start and wait for a task

`fetch.personLive`, `fetch.companyLive`, `contact.findEmail`, `contact.verifyEmail` and `contact.findPhone` start a task and return a `Task` right away. `task.id` is the task's `webhookId`.

Call `task.wait()` to poll until the task ends. When the task succeeds, the method returns its final state (`data.status`, `data.result`, `data.creditsConsumed`). When the task fails, the method raises `TaskFailedError`. Polling is free and does not count toward your rate limit.

**Live fetch**

```typescript [TypeScript SDK]
import ReverseContact, { TaskFailedError, TaskTimeoutError } from "@reverse-contact/sdk";

const client = new ReverseContact({ apiKey: process.env.RC_API_KEY });

const task = await client.fetch.personLive({ url: "https://social.com/in/janedoe" });
// Save the id first: after a restart, client.tasks.wait(id) resumes without paying for a new task.
console.log("Task id:", task.id);

try {
  const done = await task.wait({ timeout: 30 * 60 * 1000 });
  console.log(done.data.result?.firstName, "credits:", done.data.creditsConsumed);
} catch (error) {
  if (error instanceof TaskFailedError) {
    console.log("Task failed:", error.errorCode, "credits:", error.creditsConsumed);
  } else if (error instanceof TaskTimeoutError) {
    console.log("Still running, resume later with client.tasks.wait:", error.taskId);
  } else {
    throw error;
  }
}
```

How `wait()` behaves:

- Each poll asks the API to hold the answer for up to 20 seconds (`pollWait`, 0 to 20), so the result arrives as soon as the task ends. Two polls start at least `Retry-After` seconds apart, 2 seconds when the header is missing.
- `timeout` is the overall deadline in milliseconds, 30 minutes by default. When it passes, `wait()` raises `TaskTimeoutError` with `taskId` and `lastStatus`. The task may still finish: resume it with `client.tasks.wait(taskId)`.
- A task that ends with `status: "errored"` raises `TaskFailedError`, with `errorCode`, `creditsConsumed`, `result` and `notFound`. The `notFound` field is `true` for `data-not-found`, `person-not-found`, `company-not-found`, `email-not-found` and `phone-not-found`.
- `onPoll` is called with each state the SDK reads, and `signal` stops the wait (see [Timeouts and cancellation](https://docs.reversecontact.com/sdk/javascript/timeouts)).
- The SDK never starts a new task after a failure. Your code decides whether to start another task, which can be billed again.

`client.tasks.retrieve(id, { wait: 20 })` reads one state of a task without waiting for the end. [Polling](https://docs.reversecontact.com/guides/polling) describes the task lifecycle and how long a result stays available.

### Webhook delivery instead of polling

Pass `webhookUrl` when you create the task to receive the result at that HTTPS URL as `{ webhookId, data }`. Use `parseWebhookDelivery` to check the payload shape and read `webhookId`, `data` and `isError`. The `isError` field is `true` when `data.errorCode` is a non-empty string. The helper does not validate the profile itself.

**Webhook delivery**

```typescript [TypeScript SDK]
import ReverseContact, { parseWebhookDelivery } from "@reverse-contact/sdk";

const client = new ReverseContact({ apiKey: process.env.RC_API_KEY });

const task = await client.fetch.personLive({
  url: "https://social.com/in/janedoe",
  webhookUrl: "https://your-app.com/webhooks/reversecontact"
});
console.log("Store this id to match the delivery:", task.id);

// The route behind webhookUrl, as a Fetch API handler (Bun, Deno, edge runtimes).
async function handleWebhook(request: Request): Promise<Response> {
  const delivery = parseWebhookDelivery(await request.json());
  if (delivery.isError) console.log(delivery.webhookId, "failed:", delivery.data);
  else console.log(delivery.webhookId, "result:", delivery.data);
  // Answer within 10 seconds, then process the data: deduplicate on webhookId.
  return new Response(null, { status: 200 });
}
```

A task created with `webhookUrl` can still be polled with `task.wait()`. See [Webhooks](https://docs.reversecontact.com/guides/webhooks) for delivery failures and retries.

## Read a task without waiting for completion

`task.retrieve({ wait: 20 })` reads one snapshot of the same task. `task.status` holds the initial acknowledgement status. Read `snapshot.data.status` for the current state. To retrieve or wait for a saved task id, use the `retrieve()` and `wait()` methods in the [client.tasks reference](https://docs.reversecontact.com/sdk/javascript/tasks).

**Verify an email**

```typescript [TypeScript SDK]
import ReverseContact from "@reverse-contact/sdk";

const client = new ReverseContact();
const task = await client.contact.verifyEmail({ email: "jane@acme.com" });
const snapshot = await task.retrieve({ wait: 20 });
console.log(snapshot.data.status);
const done = await task.wait();
console.log(done.data.result?.status);
```

Verify Email returns `email` and a `status` of `valid`, `risky`, `invalid` or `unknown`. Find Email and Find Phone return arrays of `{ value, type }`. See [client.contact](https://docs.reversecontact.com/sdk/javascript/contact) and [client.fetch](https://docs.reversecontact.com/sdk/javascript/fetch) for their parameters.

`parseWebhookDelivery` raises `ReverseContactError` if the delivery envelope is invalid. List operations and Bulk tasks use separate wait methods, described in [Lists and Bulk enrichment](https://docs.reversecontact.com/sdk/javascript/lists-and-bulk).

Return to the [TypeScript SDK overview](https://docs.reversecontact.com/sdk/javascript).

## FAQ

### How do I wait for a live profile or Find Email result?

Call `task.wait()` on the `Task` returned by a live fetch or contact lookup. The SDK polls for free, for up to 30 minutes by default.

### How do I resume waiting after my process restarts?

Save `task.id` before waiting, then call `client.tasks.wait(taskId)` after restarting. Resuming a task avoids creating another paid lookup.

### What happens when an asynchronous SDK task fails?

`task.wait()` raises `TaskFailedError` with the task error code, credits consumed and any result. The SDK does not start a replacement task.

### Can I poll a task that also uses a webhook?

A task created with `webhookUrl` can still be polled with `task.wait()`. `parseWebhookDelivery` checks the callback envelope and identifies error deliveries.
