# Add Revealed People to Leads

> Turn revealed people into leads. Free and safe to repeat.

Requires an API key with the `write` scope.

Revealing alone never creates a lead; this call does. Only reveals that found an email count. It costs no credits and can be repeated: people who are already active leads are counted, not duplicated, and a deleted lead is restored. The plan's contact limit is checked once for the whole call, counting only people who are not leads yet. If the call would go over the limit, nothing is added.

Send `revealIds`, `personIds` or both, up to 5,000 in total.

## Body Parameters

<ParamField body="revealIds" type="array">
  Reveal ids from [List Reveals](/api-reference/lead-finder/list-reveals) or a batch.
</ParamField>

<ParamField body="personIds" type="array">
  Person ids from a search result, for people already revealed in this workspace.
</ParamField>

<ParamField body="campaignId" type="string">
  A campaign in this workspace. The people are also added to it.
</ParamField>

## Response

<ResponseField name="data" type="object">
  What happened.

  <Expandable title="data">
    <ResponseField name="added" type="integer">New leads created.</ResponseField>
    <ResponseField name="restored" type="integer">Deleted leads brought back.</ResponseField>
    <ResponseField name="alreadyInLeads" type="integer">People who were already active leads.</ResponseField>
    <ResponseField name="skipped" type="integer">Ids that were not found as a revealed email in this workspace.</ResponseField>
    <ResponseField name="addedToCampaign" type="integer">People added to `campaignId`.</ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
```bash cURL
curl -X POST "https://api.foxreach.io/api/v1/lead-finder/add-to-leads" \
  -H "X-API-Key: otr_your_key" \
  -H "Content-Type: application/json" \
  -d '{"personIds": ["per_abc123"], "campaignId": "cmp_abc123"}'
```

```python Python SDK (beta)
from foxreach import FoxReach

client = FoxReach(api_key="otr_your_key")
result = client.lead_finder.add_to_leads(person_ids=["per_abc123"], campaign_id="cmp_abc123")
```

```typescript TypeScript SDK (beta)
import { FoxReach } from "foxreach";

const client = new FoxReach({ apiKey: "otr_your_key" });
const result = await client.leadFinder.addToLeads({ personIds: ["per_abc123"], campaignId: "cmp_abc123" });
```
</RequestExample>

<ResponseExample>
```json
{
  "data": {
    "added": 1,
    "restored": 0,
    "alreadyInLeads": 0,
    "skipped": 0,
    "addedToCampaign": 1
  }
}
```
</ResponseExample>

## Errors

| Status | Description |
|--------|-------------|
| `401` | Missing, invalid, revoked or expired API key |
| `403` | API key does not have the required scope: `write` |
| `400` | `Pick at least one revealed person` when both id lists are empty, or `At most 5000 people per call` |
| `403` | `upgrade_required` with `limit`, `current` and `requested` when the contact limit would be exceeded. A missing scope also returns 403 with a plain `detail` string |
| `404` | `Lead Finder is not enabled` while Lead Finder is switched off on this environment |
| `404` | `Campaign not found` when `campaignId` is not in this workspace |
| `503` | `Lead Finder is not configured` when it is enabled but has no data provider key |

## Rate Limit

- **100 requests per minute, per API key.** Fixed 60-second window.
- Every response includes `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` (unix epoch seconds).
- A `429` response includes a `Retry-After` header (seconds until the bucket resets).

For client-side patterns (`Retry-After`, exponential backoff, monitoring `X-RateLimit-Remaining`), see [Rate Limiting](/rate-limiting).
