Marktpeil koppelen
Geef je AI-codeerassistent deze ene opdracht. Hij leest de instructie, bouwt de koppeling in jouw code en test haar met de proefsleutel.
Koppel Marktpeil aan dit project. Lees https://marktpeil.cybermatic.cloud/koppelen.md en volg de stappen daar. Test met de proefsleutel en vraag mij waar de echte sleutel moet komen.
Wat er gebeurt
- Je assistent leest de instructie: het contract, recepten per platform en de controles waarmee hij vaststelt dat het werkt.
- Hij test met de openbare proefsleutel
marktpeil-proef, die alleen voor de voorbeeldvoertuigen werkt. - Wij krijgen geen toegang tot jouw code of systemen. Alles gebeurt aan jouw kant, onder jouw toezicht.
- Voor gebruik met eigen voertuigen heb je een eigen sleutel nodig; die zet je zelf in je geheimenbeheer.
De instructie die je assistent leest
Dit is de volledige tekst, zonder verborgen stappen. Als platte tekst: /koppelen.md. Alle routes en velden: /docs.
# Marktpeil koppelen
Deze pagina is geschreven voor een AI-codeerassistent die Marktpeil in bestaande software inbouwt, en voor de ontwikkelaar die meekijkt. Alles wat nodig is staat hier. Er zijn geen verborgen stappen, en niets op deze pagina vraagt om iets buiten de koppeling zelf te wijzigen.
Marktpeil geeft op kenteken de marktwaarde van een personenauto of bestelauto: de vraagprijs die je bij een dealer voor dit voertuig mag verwachten, met een bandbreedte en een betrouwbaarheid. Stuur je de aankoopwaarde mee, dan krijg je ook een oordeel of die bij de markt past. Is er geen kenteken, dan kan het ook op een beschrijving van het voertuig (merk, model, bouwjaar); de waarde is dan minder nauwkeurig, en het antwoord zegt hoeveel. Bereik: Nederlandse kentekens, personenauto's en bestelauto's tot 3.500 kg.
## Voor de assistent: zo werk je
1. Zoek in de code waar een voertuig of aanvraag wordt aangemaakt of beoordeeld. Daar hoort de aanroep. Vraag het de ontwikkelaar als dat niet eenduidig is.
2. Bouw één functie of klasse die Marktpeil aanroept. Volg de stijl en de HTTP-bibliotheek die het project al gebruikt; voeg geen afhankelijkheid toe als het zonder kan. De recepten onderaan zijn een startpunt, geen voorschrift.
3. Lees het adres en de sleutel uit de plek waar het project zijn geheimen al bewaart (omgevingsvariabelen, een kluis, Named Credentials). Gebruik de namen `MARKTPEIL_BASE_URL` en `MARKTPEIL_API_KEY`. Zet een sleutel nooit in de code en nooit in versiebeheer; dat geldt ook voor de proefsleutel in tests.
4. Bewaar van het antwoord minimaal de velden onder "Wat je bewaart".
5. Handel fouten af volgens de tabel onder "Fouten". Een fout bij Marktpeil mag het aanmaken van een aanvraag nooit blokkeren: leg vast dat er geen waarde is, en waarom, en ga door.
6. Schrijf tests die het antwoord van Marktpeil nabootsen, zonder echte netwerkaanroep. Voer daarna de controles onder "Klaar als" één keer echt uit met de proefsleutel.
7. Laat de ontwikkelaar zien wat je hebt gewijzigd en wat hij nog moet doen: een eigen sleutel aanvragen en in het geheimenbeheer zetten. Rol niets uit zonder zijn akkoord.
## De aanroep
```
POST https://marktpeil.cybermatic.cloud/api/valuations
Content-Type: application/json
X-API-Key: <sleutel>
```
| Veld | Verplicht | Betekenis |
|---|---|---|
| `license_plate` | ja, tenzij je het voertuig beschrijft | Kenteken, met of zonder streepjes. Zie "Zonder kenteken" |
| `vat_deductible` | nee, wel aangeraden | `true` voor een btw-voertuig, `false` voor een margevoertuig |
| `mileage_km` | nee | Kilometerstand. Zie "Zonder km-stand" |
| `invoice_price` | nee | De aankoopwaarde of koopsom die je wilt toetsen |
| `invoice_price_includes_vat` | nee | Is `invoice_price` inclusief btw? Standaard `true` |
| `annual_mileage_km` | nee | Verwachte kilometers per jaar, voor de restwaarde |
| `ad_url` | nee | Link naar de advertentie van het voertuig. Die wordt gelezen en met de aankoopwaarde vergeleken; de aanroep duurt dan 10 tot 20 seconden |
Stel een time-out in van 30 seconden. Een waardebepaling duurt een halve tot één seconde.
## Wat je bewaart
| Veld | Betekenis |
|---|---|
| `valuation_id` | Nummer van deze waardebepaling; hiermee haal je haar later terug met `GET /api/valuations/{id}`. Leeg bij de proefsleutel |
| `vehicle.vehicle_id`, `vehicle.vehicle_url` | Het kenmerk van het voertuig bij Marktpeil en het adres van zijn pagina (te openen met een sleutel). Het kenmerk blijft gelijk, ook als het kenteken ontbreekt |
| `price_basis` | `excl_btw` bij bedrijfsauto's, `incl_btw` bij personenauto's. De bedragen in `market_value` staan in deze basis |
| `market_value.value` | De marktwaarde |
| `market_value.low`, `market_value.high` | De bandbreedte: de vraagprijs van een vergelijkbaar voertuig ligt hier in ongeveer acht van de tien gevallen binnen |
| `market_value.excl_vat`, `market_value.incl_vat` | Dezelfde waarde in beide prijsbases |
| `confidence.level` | `hoog`, `middel` of `laag`; `confidence.reasons` zegt waarom |
| `confidence.margin_pct` | De marge rond de waarde, in procenten: bij acht van de tien voertuigen ligt de vraagprijs binnen de waarde plus of min dit percentage. Toon dit getal naast de waarde; het is ruimer als de km-stand is geschat of als er zonder kenteken is gewaardeerd |
| `input_basis.type`, `input_basis.level` | Waarop het voertuig is herkend: `kenteken` of `beschrijving`, en bij een beschrijving hoe precies. Zie "Zonder kenteken" |
| `vehicle.mileage_km`, `vehicle.mileage_source` | De km-stand waarmee is gerekend, en of die is `opgegeven`, uit de `advertentie` komt of `geschat` is |
| `invoice_check.verdict` | Alleen als je `invoice_price` meestuurt: `in_line`, `above_market`, `far_above_market` of `below_market` |
| `invoice_check.deviation_pct` | Afwijking van de aankoopwaarde ten opzichte van de marktwaarde, in procenten |
| `warnings` | Meldingen voor de beoordelaar, zoals een importvoertuig, een open terugroepactie of een onlogische tellerstand. Toon ze |
Het antwoord bevat daarnaast de vergelijkbare voertuigen waarop de waarde rust (`comparables`, elk met een eigen `vehicle_id`), het aanbod van het voertuig zelf als dat bekend is (`own_listing`), en afgeleide waarden: verwachte transactieprijs, handelswaarde, executiewaarde en restwaarden. Die afgeleide waarden rusten op aannames die in `assumptions` staan.
## Het oordeel over de aankoopwaarde
| `invoice_check.verdict` | Wanneer |
|---|---|
| `in_line` | Binnen de bandbreedte |
| `above_market` | Boven de bandbreedte |
| `far_above_market` | Meer dan 10% boven de bovengrens, of meer dan 10% boven de vraagprijs in de eigen advertentie |
| `below_market` | Onder de bandbreedte |
De aankoopwaarde wordt eerst naar de prijsbasis van de marktwaarde omgerekend. Geef daarom met `invoice_price_includes_vat` aan in welke basis je haar aanlevert, en met `vat_deductible` of het een btw- of margevoertuig is.
## Zonder km-stand
Laat je `mileage_km` weg, dan geldt de km-stand uit de eigen advertentie van het voertuig als die bekend is. Anders wordt de km-stand geschat op wat gangbaar is voor de leeftijd en brandstof; er staat dan een waarschuwing bij, de betrouwbaarheid is één stap lager en de marge is ruimer (zie de scorekaart). Stuur de km-stand mee als je hem hebt.
## Zonder kenteken
Heb je geen kenteken (een voertuig dat nog op kenteken moet komen, een buitenlands voertuig, een offerte), laat `license_plate` dan weg en beschrijf het voertuig:
| Veld | Verplicht | Betekenis |
|---|---|---|
| `make` | ja | Merk, bijvoorbeeld `Volkswagen` |
| `model` | nee, wel sterk aangeraden | Model, bijvoorbeeld `Golf` of `Transit Custom` |
| `build_year` of `first_registration` | ja, één van beide | Bouwjaar, of liever de datum eerste toelating (`JJJJ-MM-DD`); die is nauwkeuriger |
| `version` | nee, wel aangeraden | Uitvoering zoals op de factuur of in de advertentie, bijvoorbeeld `1.5 TSI Life` |
| `fuel` | nee, wel aangeraden | `benzine`, `diesel`, `elektrisch`, `hybride`, `plugin_hybride`, `lpg` of `cng` |
| `transmission` | nee | `handgeschakeld` of `automaat` |
| `power_kw` | nee | Vermogen in kW |
| `body` | nee | `hatchback`, `stationwagen`, `suv`, `sedan`, `mpv`, `cabriolet`, `coupe` of `bedrijfswagen` |
| `kind` | nee | `personenauto` of `bedrijfsauto`; aangeraden bij een bestelauto |
| `catalog_price` | nee | Nieuwprijs inclusief btw en bpm, als je die kent |
De overige velden (`mileage_km`, `vat_deductible`, `invoice_price` en verder) werken hetzelfde als met een kenteken.
Marktpeil zoekt advertenties van voertuigen die op de beschrijving lijken en leidt daaruit af wat het met een kenteken van de RDW zou weten, zoals de catalogusprijs. Je krijgt altijd een waarde. Hoe goed die is hangt af van wat er is herkend; dat staat in `input_basis.level`:
| `input_basis.level` | Betekenis |
|---|---|
| `uitvoering` | Model herkend, en de uitvoering of het vermogen komt overeen met advertenties uit die bouwjaren |
| `model` | Model herkend; gerekend met de gangbare uitvoering van dat model |
| `merk` | Alleen het merk herkend. Een ruwe indicatie |
| `soort` | Ook het merk niet herkend. Een ruwe indicatie op basis van voertuigsoort, leeftijd en km-stand |
Hoe nauwkeurig elk niveau is staat in de scorekaart hieronder.
Verder in het antwoord: `input_basis.label` zegt hetzelfde in woorden, `input_basis.assumed` noemt wat niet is opgegeven en is ingevuld met wat bij gelijkende advertenties gangbaar is (`fuel`, `catalog_price`, `power_kw`, en `kind` bij een model dat als personenauto en als bestelauto bestaat), en `warnings` legt het uit voor de beoordelaar. `vehicle.license_plate`, `vehicle.vehicle_id` en `vehicle.vehicle_url` zijn leeg. De betrouwbaarheid is zonder kenteken nooit `hoog`; lees `confidence.margin_pct` om te weten hoe ruim je de waarde moet nemen.
Stuur je een kenteken én een beschrijving, dan gaat het kenteken voor. Kent de RDW het kenteken niet (een voorraadnummer, een buitenlands kenteken), dan wordt op de beschrijving gewaardeerd in plaats van een 404; de eerste waarschuwing zegt dat.
```bash
curl -s https://marktpeil.cybermatic.cloud/api/valuations -H 'Content-Type: application/json' -H 'X-API-Key: marktpeil-proef' -d '{"make": "Volkswagen", "model": "Golf", "build_year": 2020, "fuel": "benzine", "mileage_km": 60000}'
```
## Scorekaart: wat je aanlevert en hoe nauwkeurig de waarde dan is
Hoe meer je aanlevert, hoe kleiner de marge. Dit is gemeten, per voertuigsoort:
**Personenauto's**
| Wat je aanlevert | De helft binnen | 8 op de 10 binnen | Meer dan 25% ernaast | Betrouwbaarheid meestal |
|---|---|---|---|---|
| Kenteken en km-stand | ±5,6% | ±11% | 6% | hoog |
| Alleen het kenteken: km-stand geschat | ±8,6% | ±18% | 15% | middel |
| Zonder kenteken. Volledige beschrijving: merk, model, uitvoering, datum eerste toelating, brandstof, transmissie, vermogen, carrosserie en km-stand | ±5,9% | ±12% | 7% | middel |
| Zonder kenteken. Beschrijving op hoofdlijnen: merk, model, bouwjaar, brandstof, transmissie en km-stand | ±8,2% | ±15% | 10% | middel |
| Zonder kenteken. Minimale beschrijving: merk, model, bouwjaar en km-stand | ±9,3% | ±18% | 14% | middel |
| Zonder kenteken. Beschrijving op hoofdlijnen, zonder km-stand: merk, model, bouwjaar, brandstof en transmissie; km-stand geschat | ±10,7% | ±22% | 19% | middel |
| Zonder kenteken. Model niet herkend: merk, bouwjaar, brandstof, transmissie en km-stand | ±14,9% | ±31% | 31% | laag |
| Zonder kenteken. Merk niet herkend: bouwjaar, brandstof, transmissie en km-stand | ±24,6% | ±48% | 49% | laag |
**Bestelauto's**
| Wat je aanlevert | De helft binnen | 8 op de 10 binnen | Meer dan 25% ernaast | Betrouwbaarheid meestal |
|---|---|---|---|---|
| Kenteken en km-stand | ±8,4% | ±21% | 13% | hoog |
| Alleen het kenteken: km-stand geschat | ±12,6% | ±30% | 22% | laag |
| Zonder kenteken. Volledige beschrijving: merk, model, uitvoering, datum eerste toelating, brandstof, transmissie, vermogen, carrosserie en km-stand | ±10,8% | ±24% | 17% | middel |
| Zonder kenteken. Beschrijving op hoofdlijnen: merk, model, bouwjaar, brandstof, transmissie en km-stand | ±12,9% | ±30% | 23% | middel |
| Zonder kenteken. Minimale beschrijving: merk, model, bouwjaar en km-stand | ±14,5% | ±33% | 25% | middel |
| Zonder kenteken. Beschrijving op hoofdlijnen, zonder km-stand: merk, model, bouwjaar, brandstof en transmissie; km-stand geschat | ±15,7% | ±37% | 32% | laag |
| Zonder kenteken. Model niet herkend: merk, bouwjaar, brandstof, transmissie en km-stand | ±19,3% | ±46% | 40% | laag |
| Zonder kenteken. Merk niet herkend: bouwjaar, brandstof, transmissie en km-stand | ±23,8% | ±56% | 47% | laag |
Twee maten naast elkaar: bij de helft van de voertuigen zit de waarde binnen het eerste percentage van de vraagprijs (de mediane afwijking), bij acht van de tien binnen het tweede. Dat tweede getal is de marge die bij elke waardering in `confidence.margin_pct` staat. Gemeten op advertenties die buiten het prijsmodel en het vergelijkingsmateriaal zijn gehouden. De beschrijving in de meting is de tekst van de advertentie zelf; met een slordiger beschrijving valt de uitkomst iets slechter uit.
Twee dingen om hiermee te doen in de koppeling:
- Elk antwoord zegt in `confidence.improve` wat je kunt toevoegen om de marge te verkleinen, met de marge die dan ongeveer geldt, bijvoorbeeld `{"add": ["mileage_km"], "margin_pct": 9, "text": "Met de km-stand erbij is de marge ongeveer ±9%."}`. Toon die tekst aan de beoordelaar, of vraag het veld alsnog uit.
- De scorekaart zelf staat als gegevens op `GET https://marktpeil.cybermatic.cloud/api/scorecard` (zonder sleutel), om in de eigen software te tonen.
## Fouten
Een fout heeft altijd de vorm `{"detail": "<melding voor de gebruiker>", "code": "<code>"}`.
| Status | Code | Betekenis | Wat te doen |
|---|---|---|---|
| 401 | | Sleutel ontbreekt of klopt niet | Controleer de header `X-API-Key` |
| 403 | `demo_only` | De proefsleutel werkt alleen voor de voorbeeldvoertuigen | Gebruik een voorbeeldkenteken, of een eigen sleutel |
| 403 | `internal_only` | Dit onderdeel (advertenties en dealers doorzoeken) hoort niet bij een klantsleutel | Niet gebruiken; waarderen en voertuigpagina's werken wel |
| 404 | `not_found` | Kenteken onbekend bij de RDW | Geen waarde vastleggen, of opnieuw aanroepen met een beschrijving van het voertuig erbij (zie "Zonder kenteken"). Een voorraadnummer van een dealer is geen kenteken |
| 422 | `invalid_input` | Ongeldige invoer | Zie `detail`; niet opnieuw proberen |
| 422 | `unsupported` | Voertuig valt buiten het bereik | Niet opnieuw proberen |
| 429 | `rate_limited` | Te veel aanroepen met de proefsleutel | Na een minuut opnieuw proberen |
| 503 | `insufficient_data` | Te weinig gegevens, of de RDW is tijdelijk onbereikbaar | Na een paar minuten opnieuw proberen |
| 503 | `starting` | De dienst start op | Na een minuut opnieuw proberen |
| 500 | `internal_error` | Fout aan de kant van Marktpeil | Melden, met kenteken en tijdstip |
Bij een 503 of een time-out kun je zonder bezwaar opnieuw proberen. Elke geslaagde aanroep met een eigen sleutel legt een nieuwe waardebepaling vast.
## Proefsleutel
Om te bouwen en te testen is er een openbare proefsleutel: `marktpeil-proef`
- Hij werkt alleen voor het waarderen van deze voorbeeldvoertuigen: `N-621-FT` en `VND-20-S`.
- Het kenteken `ZZ-999-Z` geeft met de proefsleutel altijd een 404 met code `not_found`, om de foutafhandeling te testen.
- Elk ander kenteken geeft een 403 met code `demo_only`.
- Zonder kenteken werkt hij alleen voor dit voorbeeld: Volkswagen Golf uit 2020. De km-stand en de overige velden zijn vrij; een ander merk, model of bouwjaar geeft een 403 met code `demo_only`.
- Het antwoord heeft dezelfde vorm als een echt antwoord en de waarde is echt, maar `demo` is `true`, `valuation_id` is leeg en de vergelijkbare voertuigen en het eigen aanbod (`comparables`, `own_listing`) zijn weggelaten. De voertuigpagina is met de proefsleutel niet te openen.
- Er geldt een grens van 30 aanroepen per minuut voor alle gebruikers samen.
De waarden van de voorbeeldvoertuigen veranderen met de markt. Test dus op de vorm van het antwoord, niet op een vast bedrag.
## Klaar als
Voer deze controles uit tegen `https://marktpeil.cybermatic.cloud`, één keer, met de proefsleutel:
1. Een aanroep zonder sleutel geeft 401.
2. `N-621-FT` geeft 200, met `price_basis` gelijk aan `incl_btw`, `market_value.low` ≤ `market_value.value` ≤ `market_value.high`, en `confidence.level` gelijk aan `hoog`, `middel` of `laag`.
3. `VND-20-S` met `"vat_deductible": true, "invoice_price": 99999, "invoice_price_includes_vat": false` geeft 200 met `price_basis` gelijk aan `excl_btw` en `invoice_check.verdict` gelijk aan `far_above_market`.
4. `ZZ-999-Z` geeft 404 met code `not_found`, en de eigen software legt vast dat er geen waarde is en gaat door.
5. De sleutel staat niet in de code en niet in versiebeheer: zoek in de repository op de sleutel en op `X-API-Key`.
6. Alleen als de software ook zonder kenteken waardeert: `{"make": "Volkswagen", "model": "Golf", "build_year": 2020, "fuel": "benzine", "mileage_km": 60000}` geeft 200 met `input_basis.type` gelijk aan `beschrijving`, een lege `vehicle.license_plate` en een `confidence.margin_pct` groter dan 0.
## Recepten
De recepten voor curl, Python, TypeScript en PHP zijn uitgevoerd tegen deze dienst. Het recept voor Salesforce is niet in een org getest.
### curl
```bash
curl -s https://marktpeil.cybermatic.cloud/api/valuations -H 'Content-Type: application/json' -H 'X-API-Key: marktpeil-proef' -d '{"license_plate": "VND-20-S", "vat_deductible": true, "invoice_price": 30000, "invoice_price_includes_vat": false}'
```
### Python (alleen de standaardbibliotheek)
```python
import json
import os
import urllib.error
import urllib.request
class MarktpeilFout(Exception):
def __init__(self, status, code, melding):
super().__init__(f"Marktpeil {status} {code or ''}: {melding}")
self.status, self.code, self.melding = status, code, melding
def marktpeil_waardering(kenteken, btw_voertuig=None, aankoopwaarde=None, aankoop_incl_btw=False, km_stand=None):
body = {"license_plate": kenteken}
if btw_voertuig is not None:
body["vat_deductible"] = btw_voertuig
if km_stand is not None:
body["mileage_km"] = km_stand
if aankoopwaarde is not None:
body["invoice_price"] = aankoopwaarde
body["invoice_price_includes_vat"] = aankoop_incl_btw
verzoek = urllib.request.Request(
os.environ["MARKTPEIL_BASE_URL"].rstrip("/") + "/api/valuations",
data=json.dumps(body).encode(),
headers={"Content-Type": "application/json", "X-API-Key": os.environ["MARKTPEIL_API_KEY"]},
method="POST",
)
try:
with urllib.request.urlopen(verzoek, timeout=30) as antwoord:
return json.load(antwoord)
except urllib.error.HTTPError as fout:
try:
inhoud = json.load(fout)
except ValueError:
inhoud = {}
raise MarktpeilFout(fout.code, inhoud.get("code"), inhoud.get("detail")) from fout
```
### TypeScript (fetch)
```ts
export class MarktpeilFout extends Error {
status: number;
code?: string;
constructor(status: number, code: string | undefined, melding: string) {
super(`Marktpeil ${status} ${code ?? ""}: ${melding}`);
this.status = status;
this.code = code;
}
}
export async function marktpeilWaardering(invoer: {
kenteken: string;
btwVoertuig?: boolean;
aankoopwaarde?: number;
aankoopInclBtw?: boolean;
kmStand?: number;
}): Promise<any> {
const body: Record<string, unknown> = { license_plate: invoer.kenteken };
if (invoer.btwVoertuig !== undefined) body.vat_deductible = invoer.btwVoertuig;
if (invoer.kmStand !== undefined) body.mileage_km = invoer.kmStand;
if (invoer.aankoopwaarde !== undefined) {
body.invoice_price = invoer.aankoopwaarde;
body.invoice_price_includes_vat = invoer.aankoopInclBtw ?? false;
}
const antwoord = await fetch(`${process.env.MARKTPEIL_BASE_URL!.replace(/\/$/, "")}/api/valuations`, {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": process.env.MARKTPEIL_API_KEY! },
body: JSON.stringify(body),
signal: AbortSignal.timeout(30_000),
});
const inhoud = await antwoord.json().catch(() => ({}));
if (!antwoord.ok) throw new MarktpeilFout(antwoord.status, inhoud.code, inhoud.detail ?? "onbekende fout");
return inhoud;
}
```
### PHP (curl)
```php
function marktpeilWaardering(string $kenteken, ?bool $btwVoertuig = null, ?float $aankoopwaarde = null, bool $aankoopInclBtw = false, ?int $kmStand = null): array
{
$body = ['license_plate' => $kenteken];
if ($btwVoertuig !== null) { $body['vat_deductible'] = $btwVoertuig; }
if ($kmStand !== null) { $body['mileage_km'] = $kmStand; }
if ($aankoopwaarde !== null) {
$body['invoice_price'] = $aankoopwaarde;
$body['invoice_price_includes_vat'] = $aankoopInclBtw;
}
$verzoek = curl_init(rtrim(getenv('MARKTPEIL_BASE_URL'), '/') . '/api/valuations');
curl_setopt_array($verzoek, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-API-Key: ' . getenv('MARKTPEIL_API_KEY')],
CURLOPT_POSTFIELDS => json_encode($body),
]);
$antwoord = curl_exec($verzoek);
$status = curl_getinfo($verzoek, CURLINFO_RESPONSE_CODE);
if ($antwoord === false) { throw new RuntimeException('Marktpeil niet bereikbaar: ' . curl_error($verzoek)); }
$inhoud = json_decode($antwoord, true) ?? [];
if ($status !== 200) {
throw new RuntimeException(sprintf('Marktpeil %d %s: %s', $status, $inhoud['code'] ?? '', $inhoud['detail'] ?? 'onbekende fout'), $status);
}
return $inhoud;
}
```
### Salesforce (Apex)
Maak een Named Credential `Marktpeil` met als adres `https://marktpeil.cybermatic.cloud` en een External Credential die de header `X-API-Key` meestuurt. De sleutel staat dan in Salesforce en niet in de code. Een aanroep vanuit een trigger moet asynchroon, bijvoorbeeld in een Queueable.
```apex
public with sharing class MarktpeilService {
public class Waardering {
public Integer waardebepalingId;
public String prijsbasis;
public Integer waarde;
public Integer ondergrens;
public Integer bovengrens;
public String betrouwbaarheid;
public String oordeel;
public List<Object> meldingen;
}
public class MarktpeilException extends Exception {}
public static Waardering waardeer(String kenteken, Boolean btwVoertuig, Decimal aankoopwaardeExclBtw) {
Map<String, Object> body = new Map<String, Object>{ 'license_plate' => kenteken };
if (btwVoertuig != null) { body.put('vat_deductible', btwVoertuig); }
if (aankoopwaardeExclBtw != null) {
body.put('invoice_price', aankoopwaardeExclBtw);
body.put('invoice_price_includes_vat', false);
}
HttpRequest verzoek = new HttpRequest();
verzoek.setEndpoint('callout:Marktpeil/api/valuations');
verzoek.setMethod('POST');
verzoek.setHeader('Content-Type', 'application/json');
verzoek.setTimeout(30000);
verzoek.setBody(JSON.serialize(body));
HttpResponse antwoord = new Http().send(verzoek);
Map<String, Object> inhoud = (Map<String, Object>) JSON.deserializeUntyped(antwoord.getBody());
if (antwoord.getStatusCode() != 200) {
throw new MarktpeilException('Marktpeil ' + antwoord.getStatusCode() + ' ' + inhoud.get('code') + ': ' + inhoud.get('detail'));
}
Map<String, Object> markt = (Map<String, Object>) inhoud.get('market_value');
Map<String, Object> zekerheid = (Map<String, Object>) inhoud.get('confidence');
Map<String, Object> toets = (Map<String, Object>) inhoud.get('invoice_check');
Waardering w = new Waardering();
w.waardebepalingId = (Integer) inhoud.get('valuation_id');
w.prijsbasis = (String) inhoud.get('price_basis');
w.waarde = (Integer) markt.get('value');
w.ondergrens = (Integer) markt.get('low');
w.bovengrens = (Integer) markt.get('high');
w.betrouwbaarheid = (String) zekerheid.get('level');
w.oordeel = toets == null ? null : (String) toets.get('verdict');
w.meldingen = (List<Object>) inhoud.get('warnings');
return w;
}
}
```
Vanuit een aanvraag in Salesforce: het kentekenveld wordt `license_plate`, btw of marge wordt `vat_deductible` (`true` bij een btw-voertuig), en de aankoopwaarde exclusief btw wordt `invoice_price` met `invoice_price_includes_vat` op `false`.
## Wat de waarde wel en niet is
De marktwaarde is een schatting van de vraagprijs bij een dealer, op basis van actuele advertenties van vergelijkbare voertuigen en gegevens van de RDW. Het is geen taxatie: niemand heeft het voertuig gezien, en schade, staat en ontbrekende opties zijn alleen bekend als ze in een advertentie staan. Gebruik de waarde als hulpmiddel bij een beoordeling, niet als vervanging daarvan.
## Meer
- Alle routes en velden: https://marktpeil.cybermatic.cloud/docs
- De beschrijving als bestand, om een client uit te genereren: https://marktpeil.cybermatic.cloud/openapi.json
- Of de dienst werkt en de gegevens vers zijn, zonder sleutel: `GET https://marktpeil.cybermatic.cloud/api/health` (`data_fresh`)