# OEM incentives

## Endpoint

```
GET https://api.motorsdynamic.com/api/v2/offers
```

## Plan and price

| Plan | Access | Price |
| --- | --- | --- |
| Free | No | not included |
| Growth | Yes | $0.005 per call |
| Scale | Yes | $0.003 per call |
| Enterprise | Yes | contract |

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

## Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `make` | query | string | no |  |
| `model` | query | string | no |  |
| `year` | query | integer | no |  |
| `zip` | query | string | no |  |
| `offer_type` | query | string | no |  |
| `status` | query | `active` or `all` | no |  |
| `updated_since` | query | string (date-time) | no |  |
| `include` | query | `history` | no | `history` adds each offer's last 50 term changes. |
| `limit` | query | integer | no |  |
| `cursor` | query | string | no | `page.next_cursor` from the previous page, unchanged. |

## Example request

curl:

```bash
curl "https://api.motorsdynamic.com/api/v2/offers?make=Honda&zip=15205&include=history" \
  -H "x-api-key: $MD_API_KEY"
```

JavaScript:

```javascript
const res = await fetch("https://api.motorsdynamic.com/api/v2/offers?make=Honda&zip=15205&include=history", {
  headers: { "x-api-key": process.env.MD_API_KEY },
});
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.get(
    "https://api.motorsdynamic.com/api/v2/offers?make=Honda&zip=15205&include=history",
    headers={"x-api-key": os.environ["MD_API_KEY"]},
    timeout=10,
)
res.raise_for_status()
print(res.json())
```

## Example response

```json
{
  "data": [
    {
      "id": 1,
      "offer_key": "honda-crv-1",
      "make": "Honda",
      "model": "CR-V",
      "model_year": 2025,
      "trim": [
        "EX",
        "EX-L"
      ],
      "body_style": null,
      "model_code": null,
      "offer_type": "lease",
      "condition": null,
      "title": "Lease a 2025 CR-V",
      "description": null,
      "disclaimer": "Closed-end lease...",
      "value_display": "$300/mo",
      "image": null,
      "geography": {
        "postal_code": "15205",
        "region": null
      },
      "terms": {
        "cash_amount": null,
        "apr": 2.9,
        "apr_term_months": null,
        "lease_payment": 300,
        "lease_term": 36,
        "lease_due": 2999,
        "msrp": 35000,
        "selling_price": null
      },
      "valid": {
        "start_date": "2026-09-01",
        "end_date": "2026-09-30"
      },
      "status": "active",
      "removed_at": null,
      "version": {
        "number": 3,
        "last_changed_at": "2026-09-10T00:00:00.000000Z"
      },
      "first_seen_at": "2026-08-01T00:00:00.000000Z",
      "freshness": {
        "last_seen_at": "2026-09-24T05:00:00.000000Z",
        "observed_at": "2026-09-24T05:00:00.000000Z"
      },
      "provenance": {
        "source": "oem_offers",
        "source_id": 4,
        "program_id": null,
        "vendor": 1
      },
      "history": [
        {
          "change_type": "updated",
          "field": "apr",
          "old_value": "3.9",
          "new_value": "2.9",
          "changed_at": "2026-09-10T00:00:00.000000Z"
        }
      ]
    }
  ],
  "page": {
    "limit": 100,
    "has_more": false,
    "next_cursor": null
  },
  "meta": {}
}
```

## Response fields

| Field | Type | Description |
| --- | --- | --- |
| `data[]` | array of object |  |
| `data[].id` | integer |  |
| `data[].offer_key` | string or null |  |
| `data[].make` | string |  |
| `data[].model` | string or null |  |
| `data[].model_year` | integer or null |  |
| `data[].trim` | object | Trim list or object as published by the OEM. |
| `data[].body_style` | string or null |  |
| `data[].model_code` | string or null |  |
| `data[].offer_type` | string or null |  |
| `data[].condition` | string or null |  |
| `data[].title` | string or null |  |
| `data[].description` | string or null |  |
| `data[].disclaimer` | string or null |  |
| `data[].value_display` | string or null |  |
| `data[].image` | string or null |  |
| `data[].geography` | object |  |
| `data[].geography.postal_code` | string or null |  |
| `data[].geography.region` | string or null |  |
| `data[].terms` | object |  |
| `data[].terms.cash_amount` | number or null |  |
| `data[].terms.apr` | number or null |  |
| `data[].terms.apr_term_months` | integer or null |  |
| `data[].terms.lease_payment` | number or null |  |
| `data[].terms.lease_term` | integer or null |  |
| `data[].terms.lease_due` | number or null |  |
| `data[].terms.msrp` | number or null |  |
| `data[].terms.selling_price` | number or null |  |
| `data[].valid` | object |  |
| `data[].valid.start_date` | string or null |  |
| `data[].valid.end_date` | string or null |  |
| `data[].status` | `active` or `removed` |  |
| `data[].removed_at` | string or null | RFC 3339 UTC with microseconds. |
| `data[].version` | object |  |
| `data[].version.number` | integer | 1 + recorded term changes. |
| `data[].version.last_changed_at` | string or null | RFC 3339 UTC with microseconds. |
| `data[].first_seen_at` | string or null | RFC 3339 UTC with microseconds. |
| `data[].freshness` | object |  |
| `data[].freshness.last_seen_at` | string or null | RFC 3339 UTC with microseconds. |
| `data[].freshness.observed_at` | string or null | RFC 3339 UTC with microseconds. |
| `data[].freshness.age_seconds` | integer or null |  |
| `data[].provenance` | object |  |
| `data[].provenance.source` | `oem_offers` |  |
| `data[].provenance.source_id` | integer or null |  |
| `data[].provenance.program_id` | integer or null |  |
| `data[].provenance.vendor` | integer or null |  |
| `data[].history[]` | array of object |  |
| `data[].history[].change_type` | string |  |
| `data[].history[].field` | string or null |  |
| `data[].history[].old_value` | string or null |  |
| `data[].history[].new_value` | string or null |  |
| `data[].history[].changed_at` | string or null | RFC 3339 UTC with microseconds. |
| `page` | object |  |
| `page.limit` | integer |  |
| `page.has_more` | boolean |  |
| `page.next_cursor` | string or null |  |
| `meta` | 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).
