# Quotes and orders

> A machine quote prices a count for 24 hours at 0 credits. An order spends credits against that quote and delivers records under a 12 month licence.

Source: https://emailmovers.com/mydatahub/docs/quotes-and-orders
Updated: 4 October 2026

You pay once, for a complete UK record, at 1 credit each. A machine quote tells you the price before you commit, costs nothing and lasts 24 hours, and an order spends credits against it. Quoting and ordering use the same objects in the app, over REST and over MCP.

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

## Two kinds of quote

Whenever the word quote appears, it is one of two objects.

| | Machine quote | Human sales quote |
| --- | --- | --- |
| Made by | `POST /v1/quotes`, `quote_order` | The app, or an account manager |
| Lasts | 24 hours | 14 days |
| Form | JSON, signed ES256, bound to a dataset version | A PDF, payable by card or invoice link |
| Used for | Ordering by API, agent or app | Buying without an account, or sharing with a colleague |
| Id | `qte_` with `kind` machine | `qte_` with `kind` sales |

Both share the `qte_` prefix. The rest of this page is about the machine quote.

## Make a quote

Count first, then quote the count. A quote is free and needs no account.

```json
{
  "count_id": "cnt_7K2PQ4MAXN3R6TBY5WDZ",
  "field_set": "standard",
  "limit": 5000,
  "dedupe_against": "previous_orders",
  "licence": "multi_use_12m"
}
```

| Member | Meaning |
| --- | --- |
| `count_id` | A count from `POST /v1/counts`. Either case is accepted |
| `field_set` | A field set id from `GET /v1/field-sets`. Every field set costs 1 credit a record |
| `limit` | Records to buy. Left out, the whole count |
| `dedupe_against` | `none`, `previous_orders`, `crm` or `previous_orders_and_crm`. The CRM options need a `connection_id` |
| `licence` | `multi_use_12m`, or `outright` (proposed, 1.8 credits a record) |

Records you already hold under licence are always left out of a quote, whatever `dedupe_against` says. The value only adds the CRM overlap check.

## Read a quote

This response is abridged.

```json
{
  "id": "qte_01JB4M2R6T1Y5W8ZAK8Q2V7XN3",
  "kind": "machine",
  "records": 5000,
  "removed": { "already_held": 312, "suppressed": 41 },
  "credits_required": 5000,
  "credits_available": 6200,
  "gbp_ex_vat": 1495,
  "licence": { "type": "multi_use_12m", "reuse_until": "2027-09-26", "resale_prohibited": true },
  "warranty": { "policy": "replace_over_threshold_hard_bounce" },
  "expires_at": "2026-09-27T10:14:00Z",
  "blockers": []
}
```

- `records` is what you would receive, after overlap and suppression. `removed` records are never charged.
- `credits_available` and `balance_after` need an account. They are `null` when signed out, and `balance_after` is negative when you need a top-up.
- `blockers` lists why the quote cannot be ordered yet: `insufficient_credits`, `account_required`, `agent_budget_exceeded`, `dataset_unavailable` or `count_expired`.
- `signature` is an ES256 JWS over the quote's price, so one agent can hand a quote to another and both can check it against the key at `jwks_url`.

A quote made without an account is taken by the first organisation that orders it, and is then priced again on that organisation's own records and lists. The order charges the smaller of the quote and what that organisation can still be sold.

## Credits

One credit buys one complete UK record: a named email, a telephone number where held, a postal address and company fields including the Companies House number and SIC, delivered once. The price is the same in the app, the API and MCP. There are no seats, no telephone surcharge and no separate export or API credits.

| Action | Credits | Per | Status |
| --- | ---: | --- | --- |
| Count, breakdown, preview, machine quote, catalogue, title expansion | 0 | call | confirmed |
| Full UK contact record delivered, any channel or field set | 1 | record | confirmed |
| Company-only record (no named contact) | 0.1 | record | proposed |
| Contact enrichment, match found (0 if already licensed) | 1 | match | confirmed |
| Company lookup, no contact details | 0 | call | to confirm |
| Outright ownership | 1.8 | record | proposed |

Never charged: a failed lookup, a duplicate, a suppressed record, a record you already hold, a re-download of a record still under licence, and a verification re-check. Credits are whole numbers on every charge in the current build. The fractional rates are proposed and not yet in force.

The prices, ex VAT, are below (price model A, from 13 October 2026).

- One credit buys one record at the per-contact scale: 25p a record under 10,000, 22p from 10,000, 19.5p from 25,000 and 17p from 50,000. The size of a purchase picks one band for all of it, and there is no minimum order.
- A 40,000 credit pack is £1,249, and credit pack credits never expire. It is cheaper than the scale from 4,997 records.
- New customers can subscribe at £500 a month on a 12-month contract for 2,000 records a month, used or lost each month.
- Pay as you go (£299 a month) and the 12-month plan (£249 a month) stay for existing customers only.
- The free plan is 100 credits with no card.

A machine quote's `gbp_ex_vat` is the order bought the cheapest way, and its `purchase` lists what you need to buy now, cheapest first: the credits your balance does not cover, at the scale or with credit packs.

Credits and credit packs are not refundable once bought, except where the law requires, and no plan has a pro rata refund. Existing customers keep what their signed agreement says until it renews. `GET /v1/plans` returns all of it as data.

## Create an order

`POST /v1/orders` spends credits against a live `quote_id`. It needs an `Idempotency-Key` header and a confirmation, which [Spending safely](https://emailmovers.com/mydatahub/docs/spending-safely.md) explains. Without a `quote_id` the answer is `422 quote-required` and nothing is charged.

An account made by self-serve sign-up confirms its business name and that it is a UK business before its first order or enrichment, free or paid. Until a person who owns it does, in the app's Settings or with [`PATCH /v1/account`](https://emailmovers.com/mydatahub/docs/reference/rest/update-account.md), the answer is [`403 business-details-required`](https://emailmovers.com/mydatahub/docs/errors/business-details-required.md) and nothing is charged.

```json
{ "quote_id": "qte_01JB4M2R6T1Y5W8ZAK8Q2V7XN3", "name": "Leeds marketing Q4", "delivery": ["api", "csv"] }
```

The order answers `202` with the charge already made.

| Member | Meaning |
| --- | --- |
| `status` | `queued`, `building`, `verifying`, `ready`, `failed` or `cancelled` |
| `credits_charged`, `credits_remaining`, `cost_gbp` | What the order cost, the balance right after it and the GBP charge ex VAT |
| `licence_expires_at`, `licence` | When the licence ends and its terms |
| `confirmed_by` | Who approved the spend and from which client: the method, the key id, the OAuth client, the User-Agent and any client certificate fingerprint |
| `records_url`, `receipt_url` | Where to fetch the records and the signed receipt |
| `validation_report`, `buyer_kit` | Present once ready. See [Compliance receipts](https://emailmovers.com/mydatahub/docs/compliance-receipts.md) |

Every order records its caller in the audit trail and on invoices. A failed order is refunded in full and fires `order.failed`.

## Wait for the order

An order moves from `queued` to `building`, `verifying` and `ready`. Subscribe to the `order.ready` [webhook](https://emailmovers.com/mydatahub/docs/webhooks.md), or poll `GET /v1/orders/{id}` or `get_order`. Records, downloads and the receipt answer `409 order-not-ready` until the order is ready.

You can cancel while it is queued with `POST /v1/orders/{id}/cancel`. The credits come back in full, to the buckets they came from. Any later status answers `409 order-not-cancellable`, and records already delivered stay under licence.

## Fetch the records

`GET /v1/orders/{id}/records` returns pages of delivered records as JSON or CSV, with the licence block on every page. The default `limit` is 50 and the maximum 500. A page stops at about 8,000 tokens, so it can hold fewer rows than `limit`, and it always carries a `next_cursor` when more remain.

- **Pages.** Follow `next_cursor` until `has_more` is false. Over MCP, `fetch_order_records` holds at most 100 rows a page.
- **Columns.** `fields` narrows a CSV to columns of the order's field set.
- **Telephone screening.** A number's TPS and CTPS status is as of the screen date shown: `tps_ctps_status` is the result of the screen on `tps_ctps_screened_at`, valid until `tps_ctps_valid_until`, 28 days later. A clear number reads `not_screened`, with no dates, once that screen is more than 28 days before the day the file is made; a registered number stays registered. Screen the numbers you are supplied yourself before calling, and again every 28 days.
- **Download.** `GET /v1/orders/{id}/download` redirects (302) to a single-use signed URL for the CSV. It lives 5 minutes and is bound to the account.
- **Cost.** Fetching again under licence costs 0 credits. Records and the download stop after the licence ends, with the date in the problem, and the receipt stays readable.

A record objected to after delivery stays in the page, so counts and cursors still line up, but its email, telephone number and name are blank and `compliance.suppression_status` says why. See [Suppressions and objections](https://emailmovers.com/mydatahub/docs/suppressions.md).

## Licence

Every self-serve delivery is a 12 month multi-use licence, `multi_use_12m`.

| Term | Value |
| --- | --- |
| Permitted channels | email, telephone and post |
| Reuse | Until the order date plus 12 months. You can push to a CRM, re-download or refresh free until then |
| Resale | Prohibited on standard terms |
| At expiry | Records stay in your systems, the CRM property flags them, refreshes stop, and ordering again costs 1 credit |
| Terms | Data Licence and Sharing Agreement, accepted by click at checkout |

> **Proposed.** Outright ownership at 1.8 credits a record, which removes the expiry and the refresh entitlement, is a recommendation awaiting sign-off. A quote that asks for it is refused until it is switched on.

## Warranty

The policy in force today replaces records when hard bounces exceed 10 percent of an order. Quotes show it as `replace_over_threshold_hard_bounce`, with the threshold each was issued under in `threshold_percent`. `GET /v1/plans` states the current threshold.

> **Proposed.** The recommended policy replaces or re-credits any hard bounce within 30 days automatically, excludes catch-all addresses unless you opt in, and caps the automatic payout at 10 percent of an order. It is shown as `replace_any_hard_bounce_30d` once adopted. It is not in force.

## Enrich one contact

`POST /v1/contacts/enrich` returns the full record for one known person, by email or by name and company. It charges 1 credit only on a confident match, and 0 when you already hold the record or nothing matches. It spends, so it follows the same rules as an order: an `Idempotency-Key`, and a person's confirmation or an agent key that lists `enrich_contact`.

## Test mode

An `mdh_test_` key never charges. Its quote shows the price a live order would cost, and its order shows `credits_charged` 0 and leaves your live balance untouched.

Test orders are visible only to test keys and announce no webhooks. A quote settles once, in one mode: a live key cannot order a quote that a test order used. A test key needs no balance, so an account with no credits can test its integration.

## Next steps

- Understand confirmation in [Spending safely](https://emailmovers.com/mydatahub/docs/spending-safely.md).
- Prove the list is lawful with [Compliance receipts](https://emailmovers.com/mydatahub/docs/compliance-receipts.md).
- Push records onward: `POST /v1/orders/{id}/pushes` runs as a dry run unless you set `dry_run` to false, and a live push needs approval like a spend.
