Klantly Developers

API-referentie

Offertes

Offertes met hun regels: opstellen, bijwerken zolang ze concept zijn, naar de klant mailen en de uitkomst vastleggen.

Endpoints

Offertes opvragen

GET /api/v1/quotes

Een lijst van offertes, nieuwste eerst, met hun regels. Filter op status, klant of wijzigingsdatum. Met filter[status]=sent en filter[updated_since] haal je op wat er sinds je vorige synchronisatie is verstuurd.

Scope
quotes.read — Offertes lezen, met regels, bedragen en de klantgegevens erop
Vereiste functie
quotes

Queryparameters

NaamTypeOmschrijving
limit integer Aantal resultaten per pagina. van 1 tot 100 · standaard: 50
cursor string De next_cursor of prev_cursor uit meta van het vorige antwoord.
sort string Sortering op created_at of updated_at; een min-teken ervoor is aflopend. een van: -created_at, created_at, -updated_at, updated_at · standaard: -created_at
filter[status] string Alleen offertes met deze status, bijvoorbeeld sent of accepted. een van: draft, pending_review, sent, viewed, accepted, rejected, expired, completed
filter[customer_id] string (uuid) Alleen wat bij deze klant hoort.
filter[updated_since] string (date-time) Alleen wat sinds dit tijdstip is gewijzigd: ISO 8601 mét tijdzone, bijvoorbeeld 2026-09-14T10:15:00Z. Handig om te synchroniseren.

Voorbeeldverzoek

cURL
curl "https://app.klantly.com/api/v1/quotes?filter[status]=sent&sort=-updated_at" \
  -H "Authorization: Bearer $KLANTLY_API_KEY"
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('GET', 'quotes', [
    'query' => [
        'filter[status]' => 'sent',
        'sort' => '-updated_at',
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/quotes?filter[status]=sent&sort=-updated_at', {
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
  },
});

const { data } = await response.json();
Python
import os

import requests

response = requests.get(
    "https://app.klantly.com/api/v1/quotes",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
    params={
        "filter[status]": "sent",
        "sort": "-updated_at"
    },
)
data = response.json()["data"]

Antwoord 200

Het antwoord is een lijst met cursorpaginering: data bevat de objecten, meta de paginering.

Voorbeeldantwoord
{
  "data": [
    {
      "object": "quote",
      "id": "9d3f8449-afe1-4a6e-9dbc-c1dfe0f1a2ba",
      "number": "OFF-00042",
      "status": "sent",
      "title": "Veranda 400 × 300",
      "description": null,
      "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
      "customer": {
        "type": "business",
        "name": "De Vries Bouw",
        "email": "jan@example.com",
        "phone": "+31 6 12345678",
        "address": "Dorpsstraat 1",
        "postal_code": "3511 AB",
        "city": "Utrecht",
        "country": "NL",
        "company_name": "De Vries Bouw",
        "vat_number": null,
        "coc_number": null
      },
      "deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
      "pipeline_stage_id": "stg_0q8v4n61h9x0zc",
      "language": "nl",
      "currency": "EUR",
      "quote_date": "2026-09-16",
      "valid_until": "2026-09-30",
      "intro_text": null,
      "outro_text": null,
      "terms_conditions": null,
      "notes": null,
      "hide_line_amounts": false,
      "discount_percentage": "0.00",
      "discount_amount": "0.00",
      "discount_description": null,
      "subtotal": "2450.00",
      "tax_amount": "514.50",
      "total": "2964.50",
      "sent_at": null,
      "viewed_at": null,
      "accepted_at": null,
      "rejected_at": null,
      "invoice_id": null,
      "items": [
        {
          "object": "quote_item",
          "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cc",
          "type": "product",
          "name": "Veranda",
          "description": null,
          "sku": null,
          "quantity": "1.00",
          "unit": "stuk",
          "unit_price": "2450.00",
          "unit_price_incl": null,
          "discount_percentage": "0.00",
          "discount_amount": "0.00",
          "discount_description": null,
          "line_total": "2450.00",
          "line_total_incl": null,
          "is_taxable": true,
          "tax_rate": "21.00"
        }
      ],
      "created_at": "2026-09-14T10:15:00Z",
      "updated_at": "2026-09-14T10:15:00Z"
    }
  ],
  "meta": {
    "limit": 50,
    "next_cursor": "eyJpZCI6IjlkM2Y2YzFlIn0",
    "prev_cursor": null
  }
}

Mogelijke fouten

Daarnaast kan elk endpoint de algemene fouten geven, zoals een ongeldige sleutel of een bereikte limiet. Bekijk alle foutcodes.

Offerte ophalen

GET /api/v1/quotes/{quote}

Eén offerte op id, met haar regels en bedragen. Het antwoord bevat een ETag die je bij bijwerken in If-Match kunt meesturen.

Scope
quotes.read — Offertes lezen, met regels, bedragen en de klantgegevens erop
Vereiste functie
quotes

Padparameters

NaamTypeOmschrijving
quote verplicht string (uuid) De id (UUID) van de offerte.

Voorbeeldverzoek

cURL
curl "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
  -H "Authorization: Bearer $KLANTLY_API_KEY"
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('GET', 'quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
  },
});

const { data } = await response.json();
Python
import os

import requests

response = requests.get(
    "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
)
data = response.json()["data"]

Antwoord 200

Voorbeeldantwoord
{
  "data": {
    "object": "quote",
    "id": "9d3f8449-afe1-4a6e-9dbc-c1dfe0f1a2ba",
    "number": "OFF-00042",
    "status": "sent",
    "title": "Veranda 400 × 300",
    "description": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL",
      "company_name": "De Vries Bouw",
      "vat_number": null,
      "coc_number": null
    },
    "deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
    "pipeline_stage_id": "stg_0q8v4n61h9x0zc",
    "language": "nl",
    "currency": "EUR",
    "quote_date": "2026-09-16",
    "valid_until": "2026-09-30",
    "intro_text": null,
    "outro_text": null,
    "terms_conditions": null,
    "notes": null,
    "hide_line_amounts": false,
    "discount_percentage": "0.00",
    "discount_amount": "0.00",
    "discount_description": null,
    "subtotal": "2450.00",
    "tax_amount": "514.50",
    "total": "2964.50",
    "sent_at": null,
    "viewed_at": null,
    "accepted_at": null,
    "rejected_at": null,
    "invoice_id": null,
    "items": [
      {
        "object": "quote_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cc",
        "type": "product",
        "name": "Veranda",
        "description": null,
        "sku": null,
        "quantity": "1.00",
        "unit": "stuk",
        "unit_price": "2450.00",
        "unit_price_incl": null,
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "discount_description": null,
        "line_total": "2450.00",
        "line_total_incl": null,
        "is_taxable": true,
        "tax_rate": "21.00"
      }
    ],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Mogelijke fouten

Daarnaast kan elk endpoint de algemene fouten geven, zoals een ongeldige sleutel of een bereikte limiet. Bekijk alle foutcodes.

Offerte opstellen

POST /api/v1/quotes

Maakt een offerte aan bij een klant, altijd als concept. Klantly geeft hem een nummer en rekent de totalen uit; naam, adres en contactgegevens komen van de klant. Versturen doe je daarna met Offerte versturen.

Scope
quotes.write — Offertes aanmaken en wijzigen (alleen concepten), en accepteren of afwijzen namens de klant
Vereiste functie
quotes

Stuur een Idempotency-Key mee, dan maakt een nieuwe poging na een time-out geen dubbel record.

Body (JSON)

VeldTypeOmschrijving
customer_id verplicht string (uuid) De klant. Verplicht bij aanmaken; naam, adres en contactgegevens komen van de klant.
title verplicht string Titel van de offerte. Verplicht bij aanmaken. maximaal 255 tekens
items verplicht array De regels (maximaal 200). Bij invoer: een lijst met per regel name (verplicht) en optioneel type, description, sku, quantity, unit, unit_price, unit_price_incl, discount_percentage, discount_amount, discount_description, tax_rate en is_taxable. Ze vervangen alle bestaande regels.
description optioneel string Korte omschrijving; staat boven de regels. kan leeg zijn (null) · maximaal 20000 tekens
language optioneel string Taal van de offerte: nl, en, de of fr. een van: nl, en, de, fr
quote_date optioneel string (date) Offertedatum (JJJJ-MM-DD).
valid_until optioneel string (date) Geldig tot en met (JJJJ-MM-DD). Laat je hem weg, dan geldt de standaardtermijn van het bedrijf.
intro_text optioneel string Inleiding boven de regels. kan leeg zijn (null) · maximaal 20000 tekens
outro_text optioneel string Slottekst onder de regels. kan leeg zijn (null) · maximaal 20000 tekens
terms_conditions optioneel string Voorwaarden op de offerte. kan leeg zijn (null) · maximaal 20000 tekens
notes optioneel string Opmerkingen voor de klant. kan leeg zijn (null) · maximaal 20000 tekens
hide_line_amounts optioneel boolean Verbergt de bedragen per regel op de offerte; de klant ziet alleen het totaal.
discount_percentage optioneel number Korting over het totaal, in procenten. van 0 tot 100
discount_amount optioneel number Korting over het totaal, als bedrag. van 0 tot 9999999
discount_description optioneel string Waarom de korting is gegeven; staat op de offerte. kan leeg zijn (null) · maximaal 500 tekens

Voorbeeldverzoek

cURL
curl -X POST "https://app.klantly.com/api/v1/quotes" \
  -H "Authorization: Bearer $KLANTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f" \
  -d '{
  "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
  "title": "Veranda 400 × 300",
  "items": [
    {
      "name": "Veranda",
      "quantity": 1,
      "unit_price": "2450.00",
      "tax_rate": "21.00"
    }
  ]
}'
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('POST', 'quotes', [
    'headers' => [
        'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
    ],
    'json' => [
        'customer_id' => '9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70',
        'title' => 'Veranda 400 × 300',
        'items' => [
            0 => [
                'name' => 'Veranda',
                'quantity' => 1,
                'unit_price' => '2450.00',
                'tax_rate' => '21.00',
            ],
        ],
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/quotes', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
  },
  body: JSON.stringify({
  "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
  "title": "Veranda 400 × 300",
  "items": [
    {
      "name": "Veranda",
      "quantity": 1,
      "unit_price": "2450.00",
      "tax_rate": "21.00"
    }
  ]
}),
});

const { data } = await response.json();
Python
import os

import requests

response = requests.post(
    "https://app.klantly.com/api/v1/quotes",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
        "Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    },
    json={
        "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
        "title": "Veranda 400 × 300",
        "items": [
            {
                "name": "Veranda",
                "quantity": 1,
                "unit_price": "2450.00",
                "tax_rate": "21.00"
            }
        ]
    },
)
data = response.json()["data"]

Antwoord 201

Voorbeeldantwoord
{
  "data": {
    "object": "quote",
    "id": "9d3f8449-afe1-4a6e-9dbc-c1dfe0f1a2ba",
    "number": "OFF-00042",
    "status": "sent",
    "title": "Veranda 400 × 300",
    "description": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL",
      "company_name": "De Vries Bouw",
      "vat_number": null,
      "coc_number": null
    },
    "deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
    "pipeline_stage_id": "stg_0q8v4n61h9x0zc",
    "language": "nl",
    "currency": "EUR",
    "quote_date": "2026-09-16",
    "valid_until": "2026-09-30",
    "intro_text": null,
    "outro_text": null,
    "terms_conditions": null,
    "notes": null,
    "hide_line_amounts": false,
    "discount_percentage": "0.00",
    "discount_amount": "0.00",
    "discount_description": null,
    "subtotal": "2450.00",
    "tax_amount": "514.50",
    "total": "2964.50",
    "sent_at": null,
    "viewed_at": null,
    "accepted_at": null,
    "rejected_at": null,
    "invoice_id": null,
    "items": [
      {
        "object": "quote_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cc",
        "type": "product",
        "name": "Veranda",
        "description": null,
        "sku": null,
        "quantity": "1.00",
        "unit": "stuk",
        "unit_price": "2450.00",
        "unit_price_incl": null,
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "discount_description": null,
        "line_total": "2450.00",
        "line_total_incl": null,
        "is_taxable": true,
        "tax_rate": "21.00"
      }
    ],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Mogelijke fouten

Daarnaast kan elk endpoint de algemene fouten geven, zoals een ongeldige sleutel of een bereikte limiet. Bekijk alle foutcodes.

Offerte bijwerken

PATCH /api/v1/quotes/{quote}

Wijzigt alleen de velden die je meestuurt. items vervangt alle regels als geheel; die krijgen daarbij nieuwe id's. Alleen een concept kan nog veranderen: is de offerte verstuurd, dan heeft de klant hem gezien en volgt er een 409.

Scope
quotes.write — Offertes aanmaken en wijzigen (alleen concepten), en accepteren of afwijzen namens de klant
Vereiste functie
quotes

Stuur de ETag mee in If-Match, dan overschrijf je nooit per ongeluk een nieuwere versie.

Padparameters

NaamTypeOmschrijving
quote verplicht string (uuid) De id (UUID) van de offerte.

Body (JSON)

VeldTypeOmschrijving
title optioneel string Titel van de offerte. Verplicht bij aanmaken. maximaal 255 tekens
description optioneel string Korte omschrijving; staat boven de regels. kan leeg zijn (null) · maximaal 20000 tekens
language optioneel string Taal van de offerte: nl, en, de of fr. een van: nl, en, de, fr
quote_date optioneel string (date) Offertedatum (JJJJ-MM-DD).
valid_until optioneel string (date) Geldig tot en met (JJJJ-MM-DD). Laat je hem weg, dan geldt de standaardtermijn van het bedrijf.
intro_text optioneel string Inleiding boven de regels. kan leeg zijn (null) · maximaal 20000 tekens
outro_text optioneel string Slottekst onder de regels. kan leeg zijn (null) · maximaal 20000 tekens
terms_conditions optioneel string Voorwaarden op de offerte. kan leeg zijn (null) · maximaal 20000 tekens
notes optioneel string Opmerkingen voor de klant. kan leeg zijn (null) · maximaal 20000 tekens
hide_line_amounts optioneel boolean Verbergt de bedragen per regel op de offerte; de klant ziet alleen het totaal.
discount_percentage optioneel number Korting over het totaal, in procenten. van 0 tot 100
discount_amount optioneel number Korting over het totaal, als bedrag. van 0 tot 9999999
discount_description optioneel string Waarom de korting is gegeven; staat op de offerte. kan leeg zijn (null) · maximaal 500 tekens
items optioneel array De regels (maximaal 200). Bij invoer: een lijst met per regel name (verplicht) en optioneel type, description, sku, quantity, unit, unit_price, unit_price_incl, discount_percentage, discount_amount, discount_description, tax_rate en is_taxable. Ze vervangen alle bestaande regels.

Voorbeeldverzoek

cURL
curl -X PATCH "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
  -H "Authorization: Bearer $KLANTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Veranda 400 × 300 (herzien)"
}'
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('PATCH', 'quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', [
    'json' => [
        'title' => 'Veranda 400 × 300 (herzien)',
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "title": "Veranda 400 × 300 (herzien)"
}),
});

const { data } = await response.json();
Python
import os

import requests

response = requests.patch(
    "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
    json={
        "title": "Veranda 400 × 300 (herzien)"
    },
)
data = response.json()["data"]

Antwoord 200

Voorbeeldantwoord
{
  "data": {
    "object": "quote",
    "id": "9d3f8449-afe1-4a6e-9dbc-c1dfe0f1a2ba",
    "number": "OFF-00042",
    "status": "sent",
    "title": "Veranda 400 × 300",
    "description": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL",
      "company_name": "De Vries Bouw",
      "vat_number": null,
      "coc_number": null
    },
    "deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
    "pipeline_stage_id": "stg_0q8v4n61h9x0zc",
    "language": "nl",
    "currency": "EUR",
    "quote_date": "2026-09-16",
    "valid_until": "2026-09-30",
    "intro_text": null,
    "outro_text": null,
    "terms_conditions": null,
    "notes": null,
    "hide_line_amounts": false,
    "discount_percentage": "0.00",
    "discount_amount": "0.00",
    "discount_description": null,
    "subtotal": "2450.00",
    "tax_amount": "514.50",
    "total": "2964.50",
    "sent_at": null,
    "viewed_at": null,
    "accepted_at": null,
    "rejected_at": null,
    "invoice_id": null,
    "items": [
      {
        "object": "quote_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cc",
        "type": "product",
        "name": "Veranda",
        "description": null,
        "sku": null,
        "quantity": "1.00",
        "unit": "stuk",
        "unit_price": "2450.00",
        "unit_price_incl": null,
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "discount_description": null,
        "line_total": "2450.00",
        "line_total_incl": null,
        "is_taxable": true,
        "tax_rate": "21.00"
      }
    ],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Mogelijke fouten

Daarnaast kan elk endpoint de algemene fouten geven, zoals een ongeldige sleutel of een bereikte limiet. Bekijk alle foutcodes.

Offerte versturen

POST /api/v1/quotes/{quote}/send

Mailt de offerte naar de klant met het notificatiesjabloon van het bedrijf, zet de status op verstuurd en legt het tijdstip vast. Een eigen bericht komt in de mail te staan. Opnieuw versturen na een afwijzing zet de offerte terug op verstuurd.

Scope
quotes.send — Offertes naar klanten mailen
Vereiste functie
quotes

Stuur een Idempotency-Key mee, dan maakt een nieuwe poging na een time-out geen dubbel record.

Padparameters

NaamTypeOmschrijving
quote verplicht string (uuid) De id (UUID) van de offerte.

Body (JSON)

VeldTypeOmschrijving
message optioneel string Persoonlijk bericht in de mail aan de klant. kan leeg zijn (null) · maximaal 5000 tekens

Voorbeeldverzoek

cURL
curl -X POST "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/send" \
  -H "Authorization: Bearer $KLANTLY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f" \
  -d '{
  "message": "Bijgaand de offerte die we vanmorgen bespraken."
}'
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('POST', 'quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/send', [
    'headers' => [
        'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
    ],
    'json' => [
        'message' => 'Bijgaand de offerte die we vanmorgen bespraken.',
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/send', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
  },
  body: JSON.stringify({
  "message": "Bijgaand de offerte die we vanmorgen bespraken."
}),
});

const { data } = await response.json();
Python
import os

import requests

response = requests.post(
    "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/send",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
        "Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    },
    json={
        "message": "Bijgaand de offerte die we vanmorgen bespraken."
    },
)
data = response.json()["data"]

Antwoord 200

Voorbeeldantwoord
{
  "data": {
    "object": "quote",
    "id": "9d3f8449-afe1-4a6e-9dbc-c1dfe0f1a2ba",
    "number": "OFF-00042",
    "status": "sent",
    "title": "Veranda 400 × 300",
    "description": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL",
      "company_name": "De Vries Bouw",
      "vat_number": null,
      "coc_number": null
    },
    "deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
    "pipeline_stage_id": "stg_0q8v4n61h9x0zc",
    "language": "nl",
    "currency": "EUR",
    "quote_date": "2026-09-16",
    "valid_until": "2026-09-30",
    "intro_text": null,
    "outro_text": null,
    "terms_conditions": null,
    "notes": null,
    "hide_line_amounts": false,
    "discount_percentage": "0.00",
    "discount_amount": "0.00",
    "discount_description": null,
    "subtotal": "2450.00",
    "tax_amount": "514.50",
    "total": "2964.50",
    "sent_at": null,
    "viewed_at": null,
    "accepted_at": null,
    "rejected_at": null,
    "invoice_id": null,
    "items": [
      {
        "object": "quote_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cc",
        "type": "product",
        "name": "Veranda",
        "description": null,
        "sku": null,
        "quantity": "1.00",
        "unit": "stuk",
        "unit_price": "2450.00",
        "unit_price_incl": null,
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "discount_description": null,
        "line_total": "2450.00",
        "line_total_incl": null,
        "is_taxable": true,
        "tax_rate": "21.00"
      }
    ],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Mogelijke fouten

Daarnaast kan elk endpoint de algemene fouten geven, zoals een ongeldige sleutel of een bereikte limiet. Bekijk alle foutcodes.

Offerte accepteren

POST /api/v1/quotes/{quote}/accept

Legt vast dat de klant akkoord is, bijvoorbeeld na een akkoord buiten Klantly om. Een geaccepteerde offerte kan daarna niet meer worden afgewezen.

Scope
quotes.write — Offertes aanmaken en wijzigen (alleen concepten), en accepteren of afwijzen namens de klant
Vereiste functie
quotes

Stuur een Idempotency-Key mee, dan maakt een nieuwe poging na een time-out geen dubbel record.

Padparameters

NaamTypeOmschrijving
quote verplicht string (uuid) De id (UUID) van de offerte.

Voorbeeldverzoek

cURL
curl -X POST "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/accept" \
  -H "Authorization: Bearer $KLANTLY_API_KEY" \
  -H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f"
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('POST', 'quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/accept', [
    'headers' => [
        'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/accept', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
    'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
  },
});

const { data } = await response.json();
Python
import os

import requests

response = requests.post(
    "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/accept",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
        "Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    },
)
data = response.json()["data"]

Antwoord 200

Voorbeeldantwoord
{
  "data": {
    "object": "quote",
    "id": "9d3f8449-afe1-4a6e-9dbc-c1dfe0f1a2ba",
    "number": "OFF-00042",
    "status": "sent",
    "title": "Veranda 400 × 300",
    "description": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL",
      "company_name": "De Vries Bouw",
      "vat_number": null,
      "coc_number": null
    },
    "deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
    "pipeline_stage_id": "stg_0q8v4n61h9x0zc",
    "language": "nl",
    "currency": "EUR",
    "quote_date": "2026-09-16",
    "valid_until": "2026-09-30",
    "intro_text": null,
    "outro_text": null,
    "terms_conditions": null,
    "notes": null,
    "hide_line_amounts": false,
    "discount_percentage": "0.00",
    "discount_amount": "0.00",
    "discount_description": null,
    "subtotal": "2450.00",
    "tax_amount": "514.50",
    "total": "2964.50",
    "sent_at": null,
    "viewed_at": null,
    "accepted_at": null,
    "rejected_at": null,
    "invoice_id": null,
    "items": [
      {
        "object": "quote_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cc",
        "type": "product",
        "name": "Veranda",
        "description": null,
        "sku": null,
        "quantity": "1.00",
        "unit": "stuk",
        "unit_price": "2450.00",
        "unit_price_incl": null,
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "discount_description": null,
        "line_total": "2450.00",
        "line_total_incl": null,
        "is_taxable": true,
        "tax_rate": "21.00"
      }
    ],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Mogelijke fouten

Daarnaast kan elk endpoint de algemene fouten geven, zoals een ongeldige sleutel of een bereikte limiet. Bekijk alle foutcodes.

Offerte afwijzen

POST /api/v1/quotes/{quote}/reject

Legt vast dat de klant heeft afgewezen. Je kunt daarna een herziene offerte sturen; dat zet hem weer op verstuurd.

Scope
quotes.write — Offertes aanmaken en wijzigen (alleen concepten), en accepteren of afwijzen namens de klant
Vereiste functie
quotes

Stuur een Idempotency-Key mee, dan maakt een nieuwe poging na een time-out geen dubbel record.

Padparameters

NaamTypeOmschrijving
quote verplicht string (uuid) De id (UUID) van de offerte.

Voorbeeldverzoek

cURL
curl -X POST "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/reject" \
  -H "Authorization: Bearer $KLANTLY_API_KEY" \
  -H "Idempotency-Key: 6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f"
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('POST', 'quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/reject', [
    'headers' => [
        'Idempotency-Key' => '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
    ],
]);

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/reject', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
    'Idempotency-Key': '6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f',
  },
});

const { data } = await response.json();
Python
import os

import requests

response = requests.post(
    "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/reject",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
        "Idempotency-Key": "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    },
)
data = response.json()["data"]

Antwoord 200

Voorbeeldantwoord
{
  "data": {
    "object": "quote",
    "id": "9d3f8449-afe1-4a6e-9dbc-c1dfe0f1a2ba",
    "number": "OFF-00042",
    "status": "sent",
    "title": "Veranda 400 × 300",
    "description": null,
    "customer_id": "9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    "customer": {
      "type": "business",
      "name": "De Vries Bouw",
      "email": "jan@example.com",
      "phone": "+31 6 12345678",
      "address": "Dorpsstraat 1",
      "postal_code": "3511 AB",
      "city": "Utrecht",
      "country": "NL",
      "company_name": "De Vries Bouw",
      "vat_number": null,
      "coc_number": null
    },
    "deal_id": "9d3f7a20-1c5e-4d7b-8a2f-3e4c5d6f7a81",
    "pipeline_stage_id": "stg_0q8v4n61h9x0zc",
    "language": "nl",
    "currency": "EUR",
    "quote_date": "2026-09-16",
    "valid_until": "2026-09-30",
    "intro_text": null,
    "outro_text": null,
    "terms_conditions": null,
    "notes": null,
    "hide_line_amounts": false,
    "discount_percentage": "0.00",
    "discount_amount": "0.00",
    "discount_description": null,
    "subtotal": "2450.00",
    "tax_amount": "514.50",
    "total": "2964.50",
    "sent_at": null,
    "viewed_at": null,
    "accepted_at": null,
    "rejected_at": null,
    "invoice_id": null,
    "items": [
      {
        "object": "quote_item",
        "id": "9d3f856a-b0f2-4b7f-8ecd-d2e0f1a2b3cc",
        "type": "product",
        "name": "Veranda",
        "description": null,
        "sku": null,
        "quantity": "1.00",
        "unit": "stuk",
        "unit_price": "2450.00",
        "unit_price_incl": null,
        "discount_percentage": "0.00",
        "discount_amount": "0.00",
        "discount_description": null,
        "line_total": "2450.00",
        "line_total_incl": null,
        "is_taxable": true,
        "tax_rate": "21.00"
      }
    ],
    "created_at": "2026-09-14T10:15:00Z",
    "updated_at": "2026-09-14T10:15:00Z"
  }
}

Mogelijke fouten

Daarnaast kan elk endpoint de algemene fouten geven, zoals een ongeldige sleutel of een bereikte limiet. Bekijk alle foutcodes.

Offerte verwijderen

DELETE /api/v1/quotes/{quote}

Verwijdert de offerte. Alleen een concept kan weg: een verstuurde offerte blijft staan.

Scope
quotes.delete — Offertes verwijderen
Vereiste functie
quotes

Padparameters

NaamTypeOmschrijving
quote verplicht string (uuid) De id (UUID) van de offerte.

Voorbeeldverzoek

cURL
curl -X DELETE "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70" \
  -H "Authorization: Bearer $KLANTLY_API_KEY"
PHP
$client = new \GuzzleHttp\Client([
    'base_uri' => 'https://app.klantly.com/api/v1/',
    'headers' => ['Authorization' => 'Bearer ' . getenv('KLANTLY_API_KEY')],
]);

$response = $client->request('DELETE', 'quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70', {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
  },
});

const { data } = await response.json();
Python
import os

import requests

response = requests.delete(
    "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
)
data = response.json()["data"]

Antwoord 200

Voorbeeldantwoord
{
  "data": {
    "object": "note",
    "id": "9d3f7b41-2d6f-4e8c-9b3a-4f5d6e7a8b92",
    "deleted": true
  }
}

Mogelijke fouten

Daarnaast kan elk endpoint de algemene fouten geven, zoals een ongeldige sleutel of een bereikte limiet. Bekijk alle foutcodes.

Het object

Alle velden zijn altijd aanwezig; een veld zonder waarde is null.

VeldTypeOmschrijving
object string Altijd "quote".
id string (uuid) Unieke id (UUID).
number string Offertenummer, bijvoorbeeld OFF-00042; geeft Klantly zelf.
status string draft (concept), pending_review (ter controle), sent (verstuurd), viewed (bekeken), accepted (geaccepteerd), rejected (afgewezen), expired (verlopen) of completed (afgerond). een van: draft, pending_review, sent, viewed, accepted, rejected, expired, completed
title string Titel van de offerte. Verplicht bij aanmaken. kan leeg zijn (null)
description string Korte omschrijving; staat boven de regels. kan leeg zijn (null)
customer_id string (uuid) De klant. Verplicht bij aanmaken; naam, adres en contactgegevens komen van de klant. kan leeg zijn (null)
customer object De klantgegevens op de offerte, zoals ze bij het aanmaken waren.
customer.type string individual (particulier) of business (bedrijf). kan leeg zijn (null)
customer.name string Naam; bij een bedrijf de bedrijfsnaam. kan leeg zijn (null)
customer.email string E-mailadres. kan leeg zijn (null)
customer.phone string Telefoonnummer. kan leeg zijn (null)
customer.address string Straat en huisnummer. kan leeg zijn (null)
customer.postal_code string Postcode. kan leeg zijn (null)
customer.city string Plaats. kan leeg zijn (null)
customer.country string Land. kan leeg zijn (null)
customer.company_name string Bedrijfsnaam. kan leeg zijn (null)
customer.vat_number string Btw-nummer. kan leeg zijn (null)
customer.coc_number string KvK-nummer. kan leeg zijn (null)
deal_id string (uuid) De deal op het pipelinebord waar deze offerte bij hoort, of null. kan leeg zijn (null)
pipeline_stage_id string De fase waarin de offerte staat, of null. kan leeg zijn (null)
language string Taal van de offerte: nl, en, de of fr. een van: nl, en, de, fr
currency string Altijd "EUR".
quote_date string (date) Offertedatum (JJJJ-MM-DD). kan leeg zijn (null)
valid_until string (date) Geldig tot en met (JJJJ-MM-DD). Laat je hem weg, dan geldt de standaardtermijn van het bedrijf. kan leeg zijn (null)
intro_text string Inleiding boven de regels. kan leeg zijn (null)
outro_text string Slottekst onder de regels. kan leeg zijn (null)
terms_conditions string Voorwaarden op de offerte. kan leeg zijn (null)
notes string Opmerkingen voor de klant. kan leeg zijn (null)
hide_line_amounts boolean Verbergt de bedragen per regel op de offerte; de klant ziet alleen het totaal.
discount_percentage string Korting over het totaal, in procenten.
discount_amount string Korting over het totaal, als bedrag.
discount_description string Waarom de korting is gegeven; staat op de offerte. kan leeg zijn (null)
subtotal string Totaal zonder btw, als tekst met twee decimalen.
tax_amount string Btw-bedrag.
total string Totaal inclusief btw.
sent_at string (date-time) Wanneer de offerte naar de klant is gestuurd. kan leeg zijn (null)
viewed_at string (date-time) Wanneer de klant hem opende. kan leeg zijn (null)
accepted_at string (date-time) Wanneer de klant akkoord gaf. kan leeg zijn (null)
rejected_at string (date-time) Wanneer de klant afwees. kan leeg zijn (null)
invoice_id string (uuid) De factuur die uit deze offerte is gemaakt, of null. kan leeg zijn (null)
items array<object> De regels (maximaal 200). Bij invoer: een lijst met per regel name (verplicht) en optioneel type, description, sku, quantity, unit, unit_price, unit_price_incl, discount_percentage, discount_amount, discount_description, tax_rate en is_taxable. Ze vervangen alle bestaande regels.
items.object string Altijd "quote_item".
items.id string (uuid) Unieke id van de regel (UUID).
items.type string product, service, discount of fee. een van: product, service, discount, fee
items.name string Naam van de regel.
items.description string Omschrijving onder de regel. kan leeg zijn (null)
items.sku string Artikelnummer. kan leeg zijn (null)
items.quantity string Aantal.
items.unit string Eenheid, bijvoorbeeld stuk of uur. kan leeg zijn (null)
items.unit_price string Prijs per eenheid, zonder btw.
items.unit_price_incl string Prijs per eenheid inclusief btw, zoals ingevoerd. Is hij gevuld, dan rekent de regel vanaf dit bedrag (unit_price en line_total zijn daarvan afgeleid) en klopt het totaal tot op de cent met de ingevoerde prijs. null = de regel rekent vanaf unit_price. kan leeg zijn (null)
items.discount_percentage string Korting op deze regel, in procenten.
items.discount_amount string Korting op deze regel, als bedrag.
items.discount_description string Waarom de korting op deze regel is gegeven. kan leeg zijn (null)
items.line_total string Regeltotaal zonder btw, na korting.
items.line_total_incl string Regeltotaal inclusief btw, na korting. Alleen gevuld als de regel vanaf unit_price_incl rekent; anders null. kan leeg zijn (null)
items.is_taxable boolean Telt deze regel mee voor de btw.
items.tax_rate string Btw-tarief van deze regel, in procenten.
created_at string (date-time) Wanneer de offerte is aangemaakt.
updated_at string (date-time) Wanneer de offerte voor het laatst is gewijzigd.