---
title: Quickstart
description: Make your first UserCheck request, compare two responses, and block a disposable signup.
---

This guide takes you from no account to a working check. You will make two requests, compare what comes back, and use the result in a signup flow.

## 1. Get an API key

Create a [free account](https://app.usercheck.com/register). The free plan includes 1,000 credits per month and does not require a credit card.

Once you are signed in, open [API Keys](https://app.usercheck.com/api-keys) and copy your key.

## 2. Make your first request

Ask the API about an ordinary address. Replace `YOUR_API_KEY` with the key you just copied:

```bash
curl -X GET "https://api.usercheck.com/email/octocat@github.com" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

The response:

```json
{
  "status": 200,
  "email": "octocat@github.com",
  "normalized_email": "octocat@github.com",
  "domain": "github.com",
  "domain_age_in_days": 6871,
  "mx": true,
  "mx_records": [
      { "hostname": "github-com.mail.protection.outlook.com", "priority": 0 }
  ],
  "mx_providers": [
      { "slug": "microsoft", "type": "mailbox", "grade": "professional" }
  ],
  "spf": "relaxed",
  "dmarc": "quarantine",
  "disposable": false,
  "public_domain": false,
  "relay_domain": false,
  "free_subdomain": false,
  "alias": false,
  "role_account": false,
  "spam": false,
  "did_you_mean": null
}
```

Every field is documented in the [email endpoint reference](/docs/api/email-endpoint). For now the one to look at is `disposable`, which is `false`: this address is not from a temporary email service.

Pro plans also return `domain_authority`, `tld_trust`, `blocklisted`, and `disposable_provider`.

## 3. Check a disposable address

Now ask about an address from a well-known temporary email service:

```bash
curl -X GET "https://api.usercheck.com/email/jane@mailinator.com" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

```json
{
  "status": 200,
  "email": "jane@mailinator.com",
  "normalized_email": "jane@mailinator.com",
  "domain": "mailinator.com",
  "domain_age_in_days": 8431,
  "mx": true,
  "mx_records": [
      { "hostname": "mail.mailinator.com", "priority": 1 },
      { "hostname": "mail2.mailinator.com", "priority": 1 }
  ],
  "mx_providers": [],
  "spf": "strict",
  "dmarc": "reject",
  "disposable": true,
  "public_domain": false,
  "relay_domain": false,
  "free_subdomain": false,
  "alias": false,
  "role_account": false,
  "spam": true,
  "did_you_mean": null
}
```

`disposable` is now `true`, and so is `spam`.

Notice what did not change. `mx` is still `true`, `spf` is `strict`, `dmarc` is `reject`, and the domain is over 20 years old. Mailinator runs its email infrastructure carefully, so the fields that describe how well a domain is *configured* say nothing about whether its addresses are *temporary*. That is the question `disposable` answers, and it is why checking MX records alone does not catch disposable signups.

## 4. Use the result in your signup flow

```javascript
const response = await fetch(
  `https://api.usercheck.com/email/${encodeURIComponent(email)}`,
  { headers: { Authorization: `Bearer ${process.env.USERCHECK_API_KEY}` } },
);

const result = await response.json();

if (result.disposable) {
  return { error: 'Please sign up with a permanent email address.' };
}

// Store both. Mail goes to the address as submitted; the normalized form is
// the one to enforce uniqueness on, so aliases of the same mailbox, such as
// jane+trial@gmail.com, cannot open two accounts.
await createAccount({
  email: result.email,
  normalizedEmail: result.normalized_email,
});
```

This example acts on `disposable` alone. Which signals you act on, and whether you reject a signup or flag it for review, is your decision. The [response fields](/docs/api/email-endpoint) reference describes what each one means.

## Next steps

- [Email endpoint](/docs/api/email-endpoint) and [Domain endpoint](/docs/api/domain-endpoint) for every field the API returns
- [Concepts](/docs/concepts/disposable) for what individual signals mean and how to read them
- [Credits](/docs/get-started/credits) for what each request costs
- [Gates](/docs/gates/overview) to define rules in the dashboard instead of writing this logic in your application
