# Enrich a contact (spends credits)

> POST /v1/contacts/enrich. The full record for one known person, by email or by name and company.

Source: https://emailmovers.com/mydatahub/docs/reference/rest/enrich-contact

`POST /v1/contacts/enrich`

The full record for one known person, by email or by name and company. Charges 1 credit only on a confident match, and 0 when you already hold the record under licence or nothing matches. It spends, so it needs a human confirmation (MCP elicitation or a confirmation_token) or an agent key whose allowed_tools include enrich_contact, within its per-order cap and remaining monthly budget; otherwise 403 confirmation-required or agent-budget-exceeded, and 402 when the balance is short. An account made by self-serve sign-up confirms its business name and that it is a UK business first (PATCH /v1/account), or the answer is 403 business-details-required. The record comes under the Data Licence and Sharing Agreement, so the version in force is accepted as for an order, or the answer is 403 licence-acceptance-required with the approval_url. Nothing is charged on a refusal. Lawful basis for named work emails is UK GDPR Article 6(1)(f) legitimate interests; sole traders and ordinary partnerships are individual subscribers and are left out of email audiences by default.

| Property | Value |
| --- | --- |
| Endpoint | `POST https://mydatahub.emailmovers.com/v1/contacts/enrich` |
| Operation id | `enrichContact` |
| Cost | 1 credit on a confident match; 0 on no match or when already licensed. |
| Access | An API key or an OAuth 2.1 token with the scope `enrich:write`. |
| Idempotency-Key | Required. A retry never charges twice. |
| MCP tool | [`enrich_contact`](https://emailmovers.com/mydatahub/docs/reference/mcp/enrich_contact.md) |
| Tag | Lookups |

> **Not yet live.** MyDataHub v2 is built and tested locally and is not yet live. The v2 hosts open at launch, date to confirm. This page describes the contract the API is tested against.

## Request

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `MyDataHub-Version` | header | string | no | The dated API version, pinned per key when left out. Non-breaking changes ship as new dates; the path major changes only for breaking changes, with a 12 month deprecation window. |
| `Idempotency-Key` | header | string | yes | Required. A retry with the same key never charges twice; a different request with the same key returns 409. Keys are kept for the life of the organisation. |

### Body

| Member | Type | Required | Description |
| --- | --- | --- | --- |
| `email` | string (email) | no |  |
| `first_name` | string | no |  |
| `last_name` | string | no |  |
| `company_name` | string | no |  |
| `company_number` | string | no | Eight characters in upper case, such as 05046417 or SC123456. |
| `domain` | string | no |  |
| `confirmation_token` | string | no | The token the approval page on mydatahub.emailmovers.com returns once the signed-in person approves. It is bound to that person (their sub), this spend (the machine quote_id, or the enrichment or push) and an expiry no later than the quote's, and it is redeemable once. |
| `licence_accepted_version` | string | no | The version of the Data Licence and Sharing Agreement the person accepted for this record: the account's agreements.dlsa.version. Required when a person enriches in the app; an agent key carries the acceptance made with it, and a confirmation_token the one made on the approval page. |

## Example request

```bash
curl -X POST "https://mydatahub.emailmovers.com/v1/contacts/enrich" \
  -H "Authorization: Bearer $MYDATAHUB_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  --data '{
  "first_name": "Jo",
  "last_name": "Example",
  "company_number": "12345678"
}'
```

## Responses

### 200: The match, or no match.

Headers: `RateLimit`, `RateLimit-Policy`.

| Member | Type | Always present | Description |
| --- | --- | --- | --- |
| `matched` | boolean | yes |  |
| `match_confidence` | number (0 to 1) or null | yes |  |
| `already_licensed` | boolean | yes | True when you already hold the record, so it costs 0. |
| `record` | `ContactRecord` or null | yes |  |
| `record.id` | string | yes | The record id, pushed to CRMs as mydatahub_record_id. |
| `record.dataset_version` | string | yes | The immutable weekly build a count is bound to, such as 2026-W39. The last 52 stay queryable. |
| `record.contact` | object | yes |  |
| `record.email` | object or null | yes |  |
| `record.phone` | object or null | yes | Present when the field set includes telephone and a number is held. |
| `record.company` | object | yes |  |
| `record.site` | object | yes |  |
| `record.compliance` | `ComplianceObject` | yes | Carried by every preview row, order record, lookup and enrichment, and repeated as CSV columns and as the MyDataHub property group on CRM push. |
| `record.licence_expires_at` | string (date) or null | yes |  |
| `credits_charged` | number (0 or more) | yes | 1 on a confident match, otherwise 0. |
| `credits_remaining` | number (0 or more) | yes | Credits, to one decimal place: whole at 1 credit a record, fractional only where a rule is (0.1 company-only, 1.8 outright, both proposed). |
| `cost_gbp` | number (0 or more) | yes | Pounds sterling excluding VAT, to two decimal places. |
| `licence_expires_at` | string (date) or null | yes |  |

#### Example response

```json
{
  "matched": true,
  "match_confidence": 0.97,
  "already_licensed": false,
  "record": {
    "id": "contact_01JA9X2V7XN3M9R6T1Y5W8ZAK8",
    "dataset_version": "2026-W39",
    "contact": {
      "first_name": "Jo",
      "last_name": "Example",
      "title": "Marketing Director",
      "title_family": "Marketing Director",
      "job_function": "Marketing",
      "job_level_rank": 6,
      "job_level": "Director"
    },
    "email": {
      "address": "jo.example@example.co.uk",
      "type": "named",
      "deliverability_score": 88,
      "verified_at": "2026-09-10",
      "result": "ok"
    },
    "phone": {
      "e164": "+441130000001",
      "line_type": "landline",
      "tps_ctps_status": "clear",
      "screened_at": "2026-09-12"
    },
    "company": {
      "name": "Example Manufacturing Ltd",
      "companies_house_number": "12345678",
      "status": "active",
      "type": "ltd",
      "subscriber_class": "ltd",
      "sic_2007": [
        {
          "code": "25620",
          "label": "Machining"
        }
      ],
      "employee_band": "100-199",
      "turnover_band": "11M-20M",
      "website_domain": "example.co.uk"
    },
    "site": {
      "address_lines": ["1 Example Street"],
      "town": "Leeds",
      "county": "West Yorkshire",
      "postcode": "LS11 5AA",
      "region": "yorkshire_and_the_humber"
    },
    "compliance": {
      "lawful_basis": "legitimate_interests_art6_1_f",
      "lia_ref": "EM-LIA-2026-03",
      "subscriber_class": "ltd",
      "corporate_subscriber": true,
      "email_marketing_basis": "pecr_corporate_subscriber",
      "subscriber_evidence": {
        "companies_house_number": "12345678",
        "company_type": "ltd"
      },
      "article14_status": "notified",
      "article14_notified_at": "2026-06-14",
      "notice_version": "2026-02",
      "provenance": {
        "company": {
          "source": "companies_house",
          "as_of": "2026-09-21"
        },
        "contact": {
          "source": "emailmovers_research",
          "compiled_at": "2026-05-02",
          "last_verified_at": "2026-08-30",
          "method": "telephone"
        },
        "email": {
          "verified_at": "2026-09-10",
          "result": "ok",
          "provider_location": "EU"
        }
      },
      "tps_ctps_status": "clear",
      "tps_ctps_screened_at": "2026-09-12",
      "tps_ctps_valid_until": "2026-10-10",
      "suppression_status": "none",
      "record_age_days": 147,
      "attribution": "Contains public sector information licensed under the Open Government Licence v3.0"
    },
    "licence_expires_at": "2027-09-26"
  },
  "credits_charged": 1,
  "credits_remaining": 1199,
  "cost_gbp": 0.3,
  "licence_expires_at": "2027-09-26"
}
```

## Errors

Every error is a problem object with a `code` and a `next_step`. Every response carries the `RateLimit` and `RateLimit-Policy` headers; see [Rate limits](https://emailmovers.com/mydatahub/docs/rate-limits.md).

| Status | Problem codes | When |
| --- | --- | --- |
| 400 | [`invalid-request`](https://emailmovers.com/mydatahub/docs/errors/invalid-request.md), [`idempotency-key-required`](https://emailmovers.com/mydatahub/docs/errors/idempotency-key-required.md), [`unsupported-version`](https://emailmovers.com/mydatahub/docs/errors/unsupported-version.md) | The request could not be read, or an Idempotency-Key is missing. |
| 401 | [`authentication-required`](https://emailmovers.com/mydatahub/docs/errors/authentication-required.md), [`account-required`](https://emailmovers.com/mydatahub/docs/errors/account-required.md) | Sign in (OAuth) or send an API key (authentication-required), or create a free account for what the anonymous tier does not cover (account-required). |
| 402 | [`insufficient-credits`](https://emailmovers.com/mydatahub/docs/errors/insufficient-credits.md) | The balance does not cover the machine quote, which is carried here. Nothing was charged; top up on mydatahub.emailmovers.com and retry with the same quote_id. |
| 403 | [`insufficient-scope`](https://emailmovers.com/mydatahub/docs/errors/insufficient-scope.md), [`confirmation-required`](https://emailmovers.com/mydatahub/docs/errors/confirmation-required.md), [`business-details-required`](https://emailmovers.com/mydatahub/docs/errors/business-details-required.md), [`licence-acceptance-required`](https://emailmovers.com/mydatahub/docs/errors/licence-acceptance-required.md), [`dpa-acceptance-required`](https://emailmovers.com/mydatahub/docs/errors/dpa-acceptance-required.md), [`agent-budget-exceeded`](https://emailmovers.com/mydatahub/docs/errors/agent-budget-exceeded.md) | The token lacks a scope (insufficient-scope, with required_scope and a WWW-Authenticate step-up challenge); no person confirmed the spend and no agent key covers it (confirmation-required, with an approval_url); an agent key's per-order cap or monthly budget does not cover it (agent-budget-exceeded); an account made by self-serve sign-up has not yet confirmed its business name and that it is a UK business, which its first order needs (business-details-required); the order needs the Data Licence and Sharing Agreement accepted at the version in force (licence-acceptance-required); or a suppression upload comes before the organisation has accepted the Article 28 data processing agreement in force (dpa-acceptance-required). Nothing is charged. |
| 409 | [`idempotency-key-reused`](https://emailmovers.com/mydatahub/docs/errors/idempotency-key-reused.md), [`quote-expired`](https://emailmovers.com/mydatahub/docs/errors/quote-expired.md), [`order-not-ready`](https://emailmovers.com/mydatahub/docs/errors/order-not-ready.md), [`order-not-cancellable`](https://emailmovers.com/mydatahub/docs/errors/order-not-cancellable.md) | An Idempotency-Key reused with different parameters, an expired machine quote, or an object in the wrong state. |
| 422 | [`validation-failed`](https://emailmovers.com/mydatahub/docs/errors/validation-failed.md), [`quote-required`](https://emailmovers.com/mydatahub/docs/errors/quote-required.md), [`dataset-unavailable`](https://emailmovers.com/mydatahub/docs/errors/dataset-unavailable.md) | The request is not valid. errors lists every problem with a JSON pointer and did_you_mean. |
| 429 | [`rate-limited`](https://emailmovers.com/mydatahub/docs/errors/rate-limited.md) | Too many requests. Wait for Retry-After. |
| Any other failure | [`internal-error`](https://emailmovers.com/mydatahub/docs/errors/internal-error.md), [`service-unavailable`](https://emailmovers.com/mydatahub/docs/errors/service-unavailable.md), [`tps-screen-expired`](https://emailmovers.com/mydatahub/docs/errors/tps-screen-expired.md) | Something failed on our side (500 internal-error) or the service is briefly unavailable (503 service-unavailable, with Retry-After). Nothing was charged; retry with the same Idempotency-Key. A count, sample, quote or order with telephone in play is also refused with 503 tps-screen-expired, with no Retry-After, while the dataset version's TPS and CTPS screen is more than 28 days old. |
