# Clearbit Person API Replacement

This guide provides step-by-step instructions for migrating from Clearbit's Person API to Tomba's `/people/find` endpoint.

---

## API Comparison

| Feature                | Clearbit Person API                  | Tomba Person API                |
| ---------------------- | ------------------------------------ | ------------------------------- |
| **Endpoint**           | `person.clearbit.com/v2/people/find` | `api.tomba.io/v1/people/find`   |
| **Input**              | Email                                | Email                           |
| **Authentication**     | Bearer token                         | API Key + Secret headers        |
| **Rate Limit**         | 600 req/min                          | 300 req/min                     |
| **Person Data**        | ✅                                   | ✅ Enhanced                     |
| **Social Profiles**    | ✅                                   | ✅ More networks                |
| **Employment**         | ✅                                   | ✅                              |
| **Email Verification** | ❌                                   | ✅ FREE                         |
| **Phone Numbers**      | Limited                              | ✅ Validated                    |
| **LinkedIn Data**      | Basic                                | ✅ Enhanced                     |
| **Company Data**       | Basic                                | ✅ Full company info            |
| **Free Trial**         | 50 calls                             | 50 searches + 500 verifications |

---

## Endpoint Migration

### Clearbit Person API

```http
GET https://person.clearbit.com/v2/people/find?email=john@stripe.com
Authorization: Bearer sk_clearbit_xxx
```

### Tomba Person API

```http
GET https://api.tomba.io/v1/people/find?email=john@stripe.com
X-Tomba-Key: your-api-key
X-Tomba-Secret: your-secret-key
```

---

## Response Format Comparison

### Clearbit Response

```json
{
    "id": "d54c54ad-40be-4305-8a34-0ab44710b90d",
    "name": {
        "fullName": "John Doe",
        "givenName": "John",
        "familyName": "Doe"
    },
    "email": "john@stripe.com",
    "gender": null,
    "location": "San Francisco, CA, US",
    "timeZone": "America/Los_Angeles",
    "utcOffset": -8,
    "geo": {
        "city": "San Francisco",
        "state": "California",
        "stateCode": "CA",
        "country": "United States",
        "countryCode": "US",
        "lat": 37.7749,
        "lng": -122.4194
    },
    "bio": "Software Engineer passionate about building great products",
    "site": "https://johndoe.com",
    "avatar": "https://d1ts43dypk8bqh.cloudfront.net/v1/avatars/d54c54ad-40be-4305-8a34-0ab44710b90d",
    "employment": {
        "domain": "stripe.com",
        "name": "Stripe",
        "title": "Senior Software Engineer",
        "role": "engineering",
        "subRole": "engineering_manager",
        "seniority": "senior"
    },
    "facebook": {
        "handle": "johndoe"
    },
    "github": {
        "handle": "johndoe",
        "id": "123456",
        "avatar": "https://avatars.githubusercontent.com/u/123456",
        "company": "Stripe",
        "blog": "https://johndoe.com",
        "followers": 500,
        "following": 100
    },
    "twitter": {
        "handle": "johndoe",
        "id": "123456789",
        "bio": "Software Engineer @Stripe",
        "followers": 1000,
        "following": 300,
        "location": "San Francisco, CA",
        "site": "https://johndoe.com",
        "avatar": "https://pbs.twimg.com/profile_images/123456789/avatar.jpg"
    },
    "linkedin": {
        "handle": "in/johndoe"
    },
    "googleplus": {
        "handle": null
    },
    "gravatar": {
        "handle": "johndoe",
        "urls": [],
        "avatar": "https://secure.gravatar.com/avatar/123456",
        "avatars": []
    },
    "fuzzy": false,
    "emailProvider": false,
    "indexedAt": "2024-01-15T10:30:00.000Z"
}
```

### Tomba Response

```json
{
    "data": {
        "email": "john@stripe.com",
        "first_name": "John",
        "last_name": "Doe",
        "full_name": "John Doe",
        "gender": null,
        "phone_number": "+1-415-555-0123",
        "position": "Senior Software Engineer",
        "department": "Engineering",
        "seniority": "senior",
        "twitter": "johndoe",
        "linkedin": "https://www.linkedin.com/in/johndoe",
        "github": "johndoe",
        "facebook": "johndoe",
        "website": "https://johndoe.com",
        "bio": "Software Engineer passionate about building great products",
        "location": {
            "city": "San Francisco",
            "state": "California",
            "country": "United States",
            "country_code": "US"
        },
        "company": {
            "organization": "Stripe",
            "domain": "stripe.com",
            "website": "https://stripe.com",
            "industry": "Financial Services",
            "employees": "1001-5000",
            "revenue": "$100M-$500M",
            "logo": "https://d12h6n0d1mbsct.cloudfront.net/logos/stripe-com.jpg"
        },
        "verification": {
            "status": "valid",
            "result": "deliverable",
            "score": 98,
            "accept_all": false,
            "smtp_check": true,
            "mx_records": true,
            "disposable": false,
            "free_email": false
        },
        "sources": [
            {
                "uri": "https://stripe.com/about",
                "website_piece": "team",
                "extracted_on": "2024-01-15",
                "last_seen_on": "2024-01-15"
            }
        ]
    }
}
```

---

## Field Mapping

| Clearbit Field         | Tomba Field             | Notes                       |
| ---------------------- | ----------------------- | --------------------------- |
| `name.fullName`        | `full_name`             | Full name                   |
| `name.givenName`       | `first_name`            | First name                  |
| `name.familyName`      | `last_name`             | Last name                   |
| `email`                | `email`                 | Email address               |
| `gender`               | `gender`                | Gender                      |
| `bio`                  | `bio`                   | Biography                   |
| `site`                 | `website`               | Personal website            |
| `employment.title`     | `position`              | Job title                   |
| `employment.role`      | `department`            | Department                  |
| `employment.seniority` | `seniority`             | Seniority level             |
| `employment.name`      | `company.organization`  | Company name                |
| `employment.domain`    | `company.domain`        | Company domain              |
| `geo.city`             | `location.city`         | City                        |
| `geo.state`            | `location.state`        | State                       |
| `geo.country`          | `location.country`      | Country                     |
| `geo.countryCode`      | `location.country_code` | Country code                |
| `twitter.handle`       | `twitter`               | Twitter handle              |
| `linkedin.handle`      | `linkedin`              | LinkedIn URL                |
| `github.handle`        | `github`                | GitHub username             |
| `facebook.handle`      | `facebook`              | Facebook username           |
| N/A                    | `phone_number`          | **New: Validated phone**    |
| N/A                    | `verification`          | **New: Email verification** |
| N/A                    | `company.*`             | **New: Full company data**  |
| N/A                    | `sources`               | **New: Data sources**       |

---

## Code Examples

### Node.js / JavaScript

**Before (Clearbit):**

```javascript
const clearbit = require("clearbit")("sk_clearbit_xxx");

async function getPerson(email) {
    try {
        const person = await clearbit.Person.find({ email });
        return {
            name: person.name?.fullName,
            position: person.employment?.title,
            company: person.employment?.name,
            location: `${person.geo?.city}, ${person.geo?.countryCode}`,
            linkedin: person.linkedin?.handle,
        };
    } catch (error) {
        console.error("Clearbit error:", error);
        throw error;
    }
}
```

**After (Tomba):**

```javascript
const axios = require("axios");

async function getPerson(email) {
    try {
        const response = await axios.get(
            "https://api.tomba.io/v1/people/find",
            {
                params: { email },
                headers: {
                    "X-Tomba-Key": process.env.TOMBA_API_KEY,
                    "X-Tomba-Secret": process.env.TOMBA_API_SECRET,
                },
            },
        );

        const person = response.data.data;
        return {
            name: person.full_name,
            position: person.position,
            company: person.company?.organization,
            location: `${person.location?.city}, ${person.location?.country_code}`,
            linkedin: person.linkedin,
            // Bonus fields not in Clearbit
            phone: person.phone_number,
            emailValid: person.verification?.status === "valid",
            emailScore: person.verification?.score,
            companyRevenue: person.company?.revenue,
            companyEmployees: person.company?.employees,
        };
    } catch (error) {
        console.error("Tomba error:", error);
        throw error;
    }
}

// Usage
getPerson("john@stripe.com").then(console.log);
```

### Python

**Before (Clearbit):**

```python
import clearbit

clearbit.key = 'sk_clearbit_xxx'

def get_person(email):
    try:
        person = clearbit.Person.find(email=email)
        return {
            'name': person.get('name', {}).get('fullName'),
            'position': person.get('employment', {}).get('title'),
            'company': person.get('employment', {}).get('name'),
            'location': f"{person.get('geo', {}).get('city')}, {person.get('geo', {}).get('countryCode')}",
            'linkedin': person.get('linkedin', {}).get('handle')
        }
    except clearbit.errors.NotFoundError:
        return None
```

**After (Tomba):**

```python
import requests
import os

def get_person(email):
    try:
        response = requests.get(
            'https://api.tomba.io/v1/people/find',
            params={'email': email},
            headers={
                'X-Tomba-Key': os.getenv('TOMBA_API_KEY'),
                'X-Tomba-Secret': os.getenv('TOMBA_API_SECRET')
            }
        )
        response.raise_for_status()

        person = response.json()['data']
        return {
            'name': person.get('full_name'),
            'position': person.get('position'),
            'company': person.get('company', {}).get('organization'),
            'location': f"{person.get('location', {}).get('city')}, {person.get('location', {}).get('country_code')}",
            'linkedin': person.get('linkedin'),
            # Bonus fields
            'phone': person.get('phone_number'),
            'email_valid': person.get('verification', {}).get('status') == 'valid',
            'email_score': person.get('verification', {}).get('score'),
            'company_revenue': person.get('company', {}).get('revenue'),
            'company_employees': person.get('company', {}).get('employees')
        }
    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 404:
            return None
        raise

# Usage
person = get_person('john@stripe.com')
print(person)
```

### PHP

**Before (Clearbit):**

```php
<?php
require 'vendor/autoload.php';

use Clearbit\Clearbit;

Clearbit::setApiKey('sk_clearbit_xxx');

function getPerson($email) {
    try {
        $person = Clearbit::person()->find(['email' => $email]);

        return [
            'name' => $person->name->fullName ?? null,
            'position' => $person->employment->title ?? null,
            'company' => $person->employment->name ?? null,
            'location' => "{$person->geo->city}, {$person->geo->countryCode}",
            'linkedin' => $person->linkedin->handle ?? null
        ];
    } catch (\Clearbit\Errors\NotFoundError $e) {
        return null;
    }
}
```

**After (Tomba):**

```php
<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;

function getPerson($email) {
    $client = new Client();

    try {
        $response = $client->get('https://api.tomba.io/v1/people/find', [
            'query' => ['email' => $email],
            'headers' => [
                'X-Tomba-Key' => getenv('TOMBA_API_KEY'),
                'X-Tomba-Secret' => getenv('TOMBA_API_SECRET')
            ]
        ]);

        $person = json_decode($response->getBody())->data;

        return [
            'name' => $person->full_name ?? null,
            'position' => $person->position ?? null,
            'company' => $person->company->organization ?? null,
            'location' => "{$person->location->city}, {$person->location->country_code}",
            'linkedin' => $person->linkedin ?? null,
            // Bonus fields
            'phone' => $person->phone_number ?? null,
            'email_valid' => ($person->verification->status ?? '') === 'valid',
            'email_score' => $person->verification->score ?? 0,
            'company_revenue' => $person->company->revenue ?? null,
            'company_employees' => $person->company->employees ?? null
        ];
    } catch (\GuzzleHttp\Exception\ClientException $e) {
        if ($e->getResponse()->getStatusCode() === 404) {
            return null;
        }
        throw $e;
    }
}

// Usage
$person = getPerson('john@stripe.com');
print_r($person);
```

### Ruby

**Before (Clearbit):**

```ruby
require 'clearbit'

Clearbit.key = 'sk_clearbit_xxx'

def get_person(email)
  person = Clearbit::Enrichment::Person.find(email: email)

  {
    name: person.name&.fullName,
    position: person.employment&.title,
    company: person.employment&.name,
    location: "#{person.geo&.city}, #{person.geo&.countryCode}",
    linkedin: person.linkedin&.handle
  }
rescue Clearbit::NotFoundError
  nil
end
```

**After (Tomba):**

```ruby
require 'httparty'

def get_person(email)
  response = HTTParty.get(
    'https://api.tomba.io/v1/people/find',
    query: { email: email },
    headers: {
      'X-Tomba-Key' => ENV['TOMBA_API_KEY'],
      'X-Tomba-Secret' => ENV['TOMBA_API_SECRET']
    }
  )

  return nil if response.code == 404
  raise "API Error: #{response.code}" unless response.success?

  person = response.parsed_response['data']

  {
    name: person['full_name'],
    position: person['position'],
    company: person.dig('company', 'organization'),
    location: "#{person.dig('location', 'city')}, #{person.dig('location', 'country_code')}",
    linkedin: person['linkedin'],
    # Bonus fields
    phone: person['phone_number'],
    email_valid: person.dig('verification', 'status') == 'valid',
    email_score: person.dig('verification', 'score'),
    company_revenue: person.dig('company', 'revenue'),
    company_employees: person.dig('company', 'employees')
  }
end

# Usage
person = get_person('john@stripe.com')
puts person
```

---

## Enhanced Features

### Free Email Verification

Every person lookup includes FREE email verification:

```javascript
const person = response.data.data;

console.log("Email Status:", person.verification.status); // valid/invalid/unknown
console.log("Deliverable:", person.verification.result); // deliverable/undeliverable
console.log("Score:", person.verification.score); // 0-100
console.log("SMTP Check:", person.verification.smtp_check); // true/false
console.log("Disposable:", person.verification.disposable); // false
console.log("Free Email:", person.verification.free_email); // false (Gmail, etc.)
```

**Value:** Clearbit charges $0.01 per verification. With Tomba, it's FREE!

### Phone Numbers

Get validated phone numbers:

```javascript
const person = response.data.data;

if (person.phone_number) {
    console.log("Phone:", person.phone_number); // +1-415-555-0123

    // You can also use phone validator endpoint for more details
    const phoneDetails = await axios.get(
        "https://api.tomba.io/v1/phone-validator",
        {
            params: { phone: person.phone_number },
            headers: {
                /* auth headers */
            },
        },
    );

    console.log("Carrier:", phoneDetails.data.data.carrier);
    console.log("Location:", phoneDetails.data.data.location);
    console.log("Type:", phoneDetails.data.data.line_type); // mobile/landline
}
```

### Enhanced Company Data

Get full company information with person data:

```javascript
const person = response.data.data;

console.log("Company Info:");
console.log("- Name:", person.company.organization);
console.log("- Revenue:", person.company.revenue);
console.log("- Employees:", person.company.employees);
console.log("- Industry:", person.company.industry);
console.log("- Website:", person.company.website);
console.log("- Logo:", person.company.logo);
```

### Data Sources

See where the data came from:

```javascript
const person = response.data.data;

console.log("Data Sources:");
person.sources.forEach((source) => {
    console.log(`- ${source.uri}`);
    console.log(`  Found on: ${source.website_piece}`);
    console.log(`  Last seen: ${source.last_seen_on}`);
});
```

---

## Error Handling

### Clearbit Errors

```javascript
try {
    const person = await clearbit.Person.find({ email });
} catch (error) {
    if (error.type === "not_found") {
        // Person not found
    } else if (error.type === "rate_limit") {
        // Rate limited
    } else if (error.type === "invalid_request") {
        // Bad request
    }
}
```

### Tomba Errors

```javascript
try {
    const response = await axios.get("https://api.tomba.io/v1/people/find", {
        params: { email },
        headers: {
            "X-Tomba-Key": process.env.TOMBA_API_KEY,
            "X-Tomba-Secret": process.env.TOMBA_API_SECRET,
        },
    });
} catch (error) {
    if (error.response?.status === 404) {
        // Person not found
        console.log("Person not found in database");
    } else if (error.response?.status === 429) {
        // Rate limited
        console.log("Rate limit exceeded");
    } else if (error.response?.status === 400) {
        // Bad request
        console.log("Invalid email format");
    } else if (error.response?.status === 401) {
        // Authentication failed
        console.log("Invalid API credentials");
    }
}
```

---

## Testing

### Sample Test Cases

```javascript
const assert = require("assert");

describe("Person API Migration", () => {
    it("should return person data for valid email", async () => {
        const person = await getPerson("john@stripe.com");

        assert(person.name);
        assert(person.position);
        assert(person.company);
        assert(person.emailValid !== undefined); // New field
    });

    it("should return null for non-existent email", async () => {
        const person = await getPerson("notexist@example12345.com");
        assert.strictEqual(person, null);
    });

    it("should include email verification", async () => {
        const person = await getPerson("valid@stripe.com");
        assert(person.emailValid === true);
        assert(person.emailScore > 0);
    });

    it("should include phone number when available", async () => {
        const person = await getPerson("john@stripe.com");
        // Phone may or may not be available
        if (person.phone) {
            assert(person.phone.startsWith("+"));
        }
    });

    it("should include enhanced company data", async () => {
        const person = await getPerson("john@stripe.com");
        assert(person.companyRevenue);
        assert(person.companyEmployees);
    });
});
```

---

## Migration Checklist

- [ ] Update authentication to use API Key + Secret headers
- [ ] Change base URL to `api.tomba.io/v1`
- [ ] Update field mappings in your code
- [ ] Add handling for new fields (verification, phone_number, company.\*)
- [ ] Update error handling for Tomba response codes
- [ ] Test with sample emails
- [ ] Update type definitions/interfaces
- [ ] Test edge cases (invalid emails, rate limits)
- [ ] Deploy to staging environment
- [ ] Monitor API responses
- [ ] Deploy to production

---

## Next Steps

- [Company API Migration](/migration/clearbit/company-api) - Enrich company data
- [Combined API Migration](/migration/clearbit/combined-api) - Get person + company data
- [Full API Documentation](https://docs.tomba.io)

---

**Need help with migration?**

Contact our support team at [support@tomba.io](mailto:support@tomba.io) for personalized migration assistance.
