Klantly Developers

API-referentie

Bijlagen

Bestanden bij een offerte en foto's bij een werkbon: opvragen, uploaden en verwijderen. Downloaden gaat via een ondertekende link die een kwartier geldig is en geen API-sleutel nodig heeft.

Endpoints

Bijlagen opvragen

GET /api/v1/quotes/{quote}/attachments

Alle bijlagen bij deze offerte, oudste eerst, met per bestand een ondertekende downloadlink.

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/attachments" \
  -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/attachments');

$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/attachments', {
  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/attachments",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
)
data = response.json()["data"]

Antwoord 200

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

Voorbeeldantwoord
{
  "data": [
    {
      "object": "attachment",
      "id": "9d3f9e56-af10-4123-b345-e6f7a8b9c0d5",
      "quote_id": "9d3f8449-afe1-4a6e-9dbc-c1dfe0f1a2ba",
      "name": "technische-tekening.pdf",
      "mime_type": "application/pdf",
      "size": 248000,
      "description": "Tekening van de dakopbouw",
      "visible_to_customer": true,
      "download_url": "https://app.klantly.com/api/files/quote-attachment/9d3f9e56-af10-4123-b345-e6f7a8b9c0d5?expires=1789000000&signature=8f1c…",
      "created_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.

Bijlage uploaden

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

Voegt een bestand toe aan de offerte. Verstuur het als multipart/form-data met het veld file — dit is samen met de werkbonfoto het enige endpoint dat geen JSON verwacht. Toegestaan zijn pdf, jpg, jpeg, png, gif, webp, doc, docx, xls en xlsx, tot 10 MB per bestand en 20 bijlagen per offerte; daarboven volgt 403 limit_reached. Het bestandstype wordt op de inhoud gecontroleerd, niet op de naam.

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

Padparameters

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

Body (JSON)

VeldTypeOmschrijving
file verplicht string (binary) Het bestand zelf, als multipart/form-data. Maximaal 10 MB; toegestaan zijn pdf, jpg, jpeg, png, gif, webp, doc, docx, xls en xlsx.
description optioneel string Eigen omschrijving bij de bijlage. kan leeg zijn (null) · maximaal 255 tekens
visible_to_customer optioneel boolean True als de klant de bijlage bij de offerte krijgt.

Voorbeeldverzoek

cURL
curl -X POST "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/attachments" \
  -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('POST', 'quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/attachments');

$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/attachments', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.KLANTLY_API_KEY}`,
  },
});

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/attachments",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
)
data = response.json()["data"]

Antwoord 201

Voorbeeldantwoord
{
  "data": {
    "object": "attachment",
    "id": "9d3f9e56-af10-4123-b345-e6f7a8b9c0d5",
    "quote_id": "9d3f8449-afe1-4a6e-9dbc-c1dfe0f1a2ba",
    "name": "technische-tekening.pdf",
    "mime_type": "application/pdf",
    "size": 248000,
    "description": "Tekening van de dakopbouw",
    "visible_to_customer": true,
    "download_url": "https://app.klantly.com/api/files/quote-attachment/9d3f9e56-af10-4123-b345-e6f7a8b9c0d5?expires=1789000000&signature=8f1c…",
    "created_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.

Bijlage verwijderen

DELETE /api/v1/quotes/{quote}/attachments/{attachment}

Verwijdert de bijlage en het bestand zelf. Dit kan niet ongedaan worden gemaakt.

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

Padparameters

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

Voorbeeldverzoek

cURL
curl -X DELETE "https://app.klantly.com/api/v1/quotes/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/attachments/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/attachments/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/attachments/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/attachments/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.

Werkbonfoto's opvragen

GET /api/v1/work-orders/{work_order}/photos

Alle foto's bij deze werkbon, in de volgorde waarin ze op de werkbon staan, met per foto een ondertekende downloadlink.

Scope
work_orders.read — Werkbonnen lezen, met naam, adres en contactgegevens van de klant
Vereiste functie
work_orders

Padparameters

NaamTypeOmschrijving
work_order verplicht string (uuid) De id (UUID) van de werkbon.

Voorbeeldverzoek

cURL
curl "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos" \
  -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', 'work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos');

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos', {
  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/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos",
    headers={
        "Authorization": f"Bearer {os.environ['KLANTLY_API_KEY']}",
    },
)
data = response.json()["data"]

Antwoord 200

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

Voorbeeldantwoord
{
  "data": [
    {
      "object": "work_order_photo",
      "id": "9d3f9f67-b021-4234-c456-f7a8b9c0d1e6",
      "work_order_id": "9d3f8328-9ed0-4f5d-8cab-b0cedfe0f1a9",
      "kind": "after",
      "caption": "Dakgoot na montage",
      "download_url": "https://app.klantly.com/api/files/quote-attachment/9d3f9e56-af10-4123-b345-e6f7a8b9c0d5?expires=1789000000&signature=8f1c…",
      "created_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.

Werkbonfoto uploaden

POST /api/v1/work-orders/{work_order}/photos

Voegt een foto toe aan de werkbon; hij komt ook in de pdf. Verstuur hem als multipart/form-data met het veld file. Alleen afbeeldingen (jpg, jpeg, png, gif, webp), tot 10 MB per foto en 30 foto’s per werkbon. Met kind geef je aan of de foto van vóór of ná het werk is.

Scope
work_orders.write — Werkbonnen aanmaken en wijzigen, en de status aanpassen (afronden kan een reviewverzoek sturen)
Vereiste functie
work_orders

Padparameters

NaamTypeOmschrijving
work_order verplicht string (uuid) De id (UUID) van de werkbon.

Body (JSON)

VeldTypeOmschrijving
file verplicht string (binary) De foto zelf, als multipart/form-data. Maximaal 10 MB; toegestaan zijn jpg, jpeg, png, gif en webp.
kind optioneel string before (vóór het werk), after (erna) of other. een van: before, after, other
caption optioneel string Bijschrift bij de foto. kan leeg zijn (null) · maximaal 255 tekens

Voorbeeldverzoek

cURL
curl -X POST "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos" \
  -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('POST', 'work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos');

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

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

import requests

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

Antwoord 201

Voorbeeldantwoord
{
  "data": {
    "object": "work_order_photo",
    "id": "9d3f9f67-b021-4234-c456-f7a8b9c0d1e6",
    "work_order_id": "9d3f8328-9ed0-4f5d-8cab-b0cedfe0f1a9",
    "kind": "after",
    "caption": "Dakgoot na montage",
    "download_url": "https://app.klantly.com/api/files/quote-attachment/9d3f9e56-af10-4123-b345-e6f7a8b9c0d5?expires=1789000000&signature=8f1c…",
    "created_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.

Werkbonfoto verwijderen

DELETE /api/v1/work-orders/{work_order}/photos/{photo}

Verwijdert de foto en het bestand zelf. Dit kan niet ongedaan worden gemaakt.

Scope
work_orders.write — Werkbonnen aanmaken en wijzigen, en de status aanpassen (afronden kan een reviewverzoek sturen)
Vereiste functie
work_orders

Padparameters

NaamTypeOmschrijving
work_order verplicht string (uuid) De id (UUID) van de werkbon.
photo verplicht string (uuid) De id (UUID) van de foto.

Voorbeeldverzoek

cURL
curl -X DELETE "https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos/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', 'work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70');

$data = json_decode((string) $response->getBody(), true)['data'];
JavaScript
const response = await fetch('https://app.klantly.com/api/v1/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos/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/work-orders/9d3f6c1e-4b2a-4c8e-9f1a-2b3c4d5e6f70/photos/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 "attachment".
id string (uuid) Id van de bijlage.
quote_id string (uuid) De offerte waar de bijlage bij hoort.
name string De bestandsnaam zoals hij werd geüpload. kan leeg zijn (null)
mime_type string Het bestandstype, zoals application/pdf. kan leeg zijn (null)
size integer De grootte in bytes. kan leeg zijn (null)
description string Eigen omschrijving bij de bijlage. kan leeg zijn (null)
visible_to_customer boolean True als de klant de bijlage bij de offerte krijgt.
download_url string (uri) Een ondertekende link naar het bestand, een kwartier geldig en zonder API-sleutel te openen. Vraag hem opnieuw op als hij verlopen is.
created_at string (date-time) Wanneer de bijlage werd toegevoegd (UTC).