# Register a dealer

Idempotent. A host MotorsDynamic already crawls only gains the agency entitlement. A new host
becomes a discovery-tier site (`serving=false`): it is crawled in shadow and nothing is
published until it is promoted. Needs scope `v2:write` (keys) or role admin and above (sessions).
Returns 201 when anything was created, 200 when everything already existed.

## Endpoint

```
POST https://api.motorsdynamic.com/api/v2/dealers
```

## Plan and price

| Plan | Access | Price |
| --- | --- | --- |
| Free | No | not included |
| Growth | No | not included |
| Scale | No | not included |
| Enterprise | Yes | contract |

A call is billed when it answers 2xx. See [pricing](https://developers.motorsdynamic.com/pricing.md).

## Request body

| Field | Type | Description |
| --- | --- | --- |
| `url` | string | Website, for example https://www.exampledealer.com |
| `name` | string |  |
| `agency_id` | integer | Required only when the credential can act for more than one agency. |
| `kinds[]` | array of inventory or offers or oem_inventory or media or stickers or specials |  |

## Example request

curl:

```bash
curl -X POST "https://api.motorsdynamic.com/api/v2/dealers" \
  -H "x-api-key: $MD_API_KEY" \
  -H "content-type: application/json" \
  -d '{"url":"https://www.newdealer.com","name":"New Dealer","kinds":["inventory"]}'
```

JavaScript:

```javascript
const res = await fetch("https://api.motorsdynamic.com/api/v2/dealers", {
  method: "POST",
  headers: { "x-api-key": process.env.MD_API_KEY, "content-type": "application/json" },
  body: JSON.stringify({"url":"https://www.newdealer.com","name":"New Dealer","kinds":["inventory"]}),
});
if (!res.ok) throw new Error(`${res.status} ${(await res.json()).error}`);
const data = await res.json();
console.log(data);
```

Python:

```python
import os, requests

res = requests.post(
    "https://api.motorsdynamic.com/api/v2/dealers",
    headers={"x-api-key": os.environ["MD_API_KEY"]},
    json={"url":"https://www.newdealer.com","name":"New Dealer","kinds":["inventory"]},
    timeout=10,
)
res.raise_for_status()
print(res.json())
```

## Example response

```json
{
  "data": {
    "id": 1000000001,
    "url": "https://newdealer.com",
    "host": "newdealer.com",
    "name": "New Dealer",
    "city": null,
    "state": null,
    "platform": null,
    "tier": "discovery",
    "crawl": {
      "owner": "legacy",
      "serving": false,
      "next_crawl_at": "2026-09-24T10:00:00.000000Z",
      "last_complete_at": null
    },
    "freshness": {
      "last_seen_at": null
    },
    "provenance": {
      "source": "v2_domains"
    },
    "agency_id": 2,
    "created": {
      "site": true,
      "targets": [
        "inventory"
      ],
      "entitlement": true
    }
  }
}
```

## Response fields

| Field | Type | Description |
| --- | --- | --- |
| `data` | object |  |

## Errors

| Status | Code | When |
| --- | --- | --- |
| 400 | `invalid_parameter` | A parameter is missing or malformed. The message names it. |
| 401 | `invalid_api_key` | The key is missing, revoked or mistyped. |
| 402 | `plan_required` | The endpoint is on a higher plan. The body names the plan and links to the upgrade. |
| 403 | `not_entitled` | The key may not read this dealer or source. |
| 429 | `rate_limited or quota_exceeded` | Slow down (see `Retry-After`), or the Free monthly calls are used up. |
| 504 | `query_timeout` | The query passed its 4 second budget. Narrow the filters. Not billed. |

Every error has the same body: `{ "error": "<code>", "message": "..." }`. Full list: [errors](https://developers.motorsdynamic.com/docs/errors.md).
