---
title: "Validate contact data in Reply.io"
url: "https://lookvalid.com/integrations/reply-io.md"
canonical_url: "https://lookvalid.com/integrations/reply-io"
last_updated: "2026-10-22"
type: "how-to"
summary: "Subscribe a Reply.io webhook to call events and validate the number behind each call, using the contact custom fields the event carries."
related: ["https://lookvalid.com/integrations.md", "https://lookvalid.com/docs/api/phone.md", "https://lookvalid.com/docs/quickstart.md"]
---

# Validate contact data in Reply.io

Subscribe a Reply.io webhook to call events and validate the number behind each call, using the contact custom fields the event carries.

Reply.io runs email, calls and other steps in one sequence, so a contact whose phone is formatted loosely or sits in the wrong country can make the call step fail while the rest of the sequence keeps going. The call outcome then gets logged against a contact that was never reachable by that number to begin with.

## What LookValid checks

- [Phone Numbering-Plan Validation](https://lookvalid.com/products/phone.md): Returns E.164 and display formats, the country and the number type the numbering plan assigns for a contact number. It does not say whether the number is active. (1 credit per valid number)
- [Phone Spam Check](https://lookvalid.com/products/phone-spam.md): Shows consumer complaint counts for a number as reports nobody has checked, which tells a rep a number has a history before the call step runs. (1 credit per number with complaints on record)
- [Carrier Lookup (original carrier)](https://lookvalid.com/products/carrier-lookup.md): For US numbers, shows the carrier first assigned the number block with its state and rate center. Porting is not reflected. (1 credit per lookup (numbers outside the covered numbering plan areas are free))
- [Email Domain Check](https://lookvalid.com/products/email-domain-check.md): Checks the contact email domain for mail servers and throwaway providers when an email bounces, without contacting the mail server. (1 credit per address checked)

## Connect it in four steps

1. Open a LookValid account and create an API key.
2. Set the key as the LOOKVALID_API_KEY environment variable of the webhook handler, and enable includeProspectCustomFields on the Reply.io subscription so the contact custom fields arrive in contact_custom_fields.
3. Pass the phone from the event contact to the function: it posts to the phone endpoint, returns None when nothing was found and raises with the error code and fix if the API refuses.
4. Write the three values back to the contact as custom fields through the Reply.io v3 API, using your Reply.io key as a bearer token, so later sequence steps can read them.

the handler for a Reply.io webhook subscription that receives contact call events The call is `POST https://YOUR_API_HOST/v1/phone`.

```python
import json
import os
import urllib.error
import urllib.request

API_URL = "https://YOUR_API_HOST/v1/phone"


def validate_reply_contact_phone(value):
    request = urllib.request.Request(
        API_URL,
        data=json.dumps({
            "phone": value,
        }).encode(),
        headers={
            "Authorization": "Bearer " + os.environ["LOOKVALID_API_KEY"],
            "Content-Type": "application/json",
        },
        method="POST",
    )
    try:
        with urllib.request.urlopen(request, timeout=30) as response:
            result = json.load(response)
    except urllib.error.HTTPError as error:
        failure = json.load(error)["error"]
        raise RuntimeError(failure["code"] + ": " + failure["fix"])
    if not result["found"]:
        return None
    return {
        "phone_e164": result.get("data", {}).get("e164"),
        "phone_type": result.get("data", {}).get("number_type"),
        "phone_country": result.get("data", {}).get("country"),
    }
```

| Response field | Goes into |
| --- | --- |
| `data.e164` | phone_e164 |
| `data.number_type` | phone_type |
| `data.country` | phone_country |

## Without code

The webhook subscription delivers each event to a URL of your choice, so an automation platform with a generic HTTP request step can be the receiver without a dedicated app. After the catch trigger, send the contact phone to the phone endpoint with your key in a bearer header, then add an HTTP step that updates the contact through the Reply.io API.

## Questions

### Does every event cost credits?

Only the lookups your handler makes. Each one draws credits from your LookValid balance, and the pricing page lists the amount for the phone check.

### What will the check not tell me about a contact number?

Whether the line is live, who the carrier is now, or who owns it. It reads the numbering plan only.

### Where does the LookValid key sit in a Reply.io integration?

In the handler environment as LOOKVALID_API_KEY. The Reply.io key that calls its own API is a separate bearer token, kept in another variable.

## Sources

- [Reply.io API reference: introduction](https://docs.reply.io/api-reference/introduction), read 2026-10-18
- [Reply.io docs: webhook event payloads](https://docs.reply.io/webhook-event-payloads.md), read 2026-10-18

## Related

- [LookValid integrations](https://lookvalid.com/integrations.md)
- [Phone Numbering-Plan Validation reference](https://lookvalid.com/docs/api/phone.md)
- [Quickstart](https://lookvalid.com/docs/quickstart.md)
