Customers API
Customers ermöglichen es Ihnen, Ihre Geschäftskunden zu verwalten. Jeder Customer hat Kontaktinformationen, Adressdetails, Standard-Stundensätze und kann mit Projekten, Rechnungen und Zeiterfassung verknüpft werden.
Customer-Objekt
{
"id": 410,
"company_id": 123,
"userId": 456,
"companyName": "Muster AG",
"number": 1001,
"contactName": null,
"careOf": null,
"poBox": null,
"department": null,
"street": "Beispielstrasse 15",
"zip": "8001",
"city": "Zürich",
"country": "Schweiz",
"website": null,
"phone": null,
"defaultHourlyRate": 150.00,
"created_at": "2023-06-04T15:23:12.000000Z",
"updated_at": "2025-07-17T10:54:45.000000Z",
"archived": false,
"email": "max@example.com",
"invoice_address": null
}
Attribute
Feld | Typ | Beschreibung |
---|---|---|
id | integer | Eindeutige Customer-ID |
company_id | integer | ID der zugehörigen Firma |
userId | integer | ID des Benutzers, der den Customer erstellt hat |
companyName | string | Name des Kundenunternehmens (erforderlich) |
number | integer|null | Kundennummer (automatisch generiert wenn nicht angegeben) |
contactName | string|null | Name der Ansprechperson |
careOf | string|null | c/o Zusatz für Adresse |
poBox | string|null | Postfach |
department | string|null | Abteilung |
street | string|null | Strassenadresse |
zip | string|null | Postleitzahl |
city | string|null | Stadt |
country | string|null | Land |
website | string|null | Website-URL |
phone | string|null | Telefonnummer |
email | string|null | E-Mail-Adresse |
defaultHourlyRate | decimal|null | Standard-Stundensatz (CHF) |
invoice_address | string|null | Separate Rechnungsadresse |
archived | boolean | Ob der Customer archiviert ist |
created_at | datetime | Erstellungsdatum |
updated_at | datetime | Datum der letzten Aktualisierung |
Endpoints
Alle Customers auflisten
GET /companies/{company}/customers
Ruft eine paginierte Liste aller Customers der Firma ab.
Parameter
Parameter | Typ | Standard | Beschreibung |
---|---|---|---|
page | integer | 1 | Seitennummer |
per_page | integer | 15 | Anzahl Customers pro Seite (max. 100) |
filter[id] | integer | - | Filtern nach spezifischer Customer-ID |
filter[archived] | boolean | - | Filtern nach Archivierungsstatus |
filter[expenses] | boolean | - | Filtern nach offenen Ausgaben |
filter[times] | integer | - | Filtern nach offenen Zeiten (Minuten) |
Response
Erweiterte Listen-Response
Die Listen-Response enthält zusätzliche berechnete Felder (openExpensesSum
, openTimesSum
, openInvoiceSum
) und vereinfachte Contact-Informationen für bessere Performance.
{
"data": [
{
"id": 410,
"company_id": 123,
"userId": 456,
"companyName": "Muster AG",
"number": 1001,
"street": "Beispielstrasse 15",
"zip": "8001",
"city": "Zürich",
"country": "Schweiz",
"defaultHourlyRate": 150.00,
"email": "max@example.com",
"archived": false,
"openExpensesSum": {
"sum": 245.75,
"sumFormatted": "245.75"
},
"openTimesSum": {
"hours": 3,
"minutes": 45,
"totalMinutes": 225,
"readable": "03:45"
},
"openInvoiceSum": "1,250.00",
"contacts": [
{
"id": 175,
"name": "Max Muster",
"is_primary": true,
"archived": false
}
]
}
],
"links": {
"first": "https://app.milkee.ch/api/v2/companies/123/customers?page=1",
"last": "https://app.milkee.ch/api/v2/companies/123/customers?page=3",
"prev": null,
"next": "https://app.milkee.ch/api/v2/companies/123/customers?page=2"
},
"meta": {
"current_page": 1,
"last_page": 3,
"per_page": 15,
"total": 37
}
}
Beispiel
curl -H "Authorization: Bearer 1|abcdef123456789..." \
"https://app.milkee.ch/api/v2/companies/123/customers"
Neuen Customer erstellen
POST /companies/{company}/customers
Erstellt einen neuen Customer für die angegebene Firma.
Request Body
{
"companyName": "Neue Firma AG",
"contactName": "Anna Beispiel",
"street": "Beispielstrasse 456",
"zip": "8002",
"city": "Zürich",
"country": "Schweiz",
"email": "contact@example.com",
"phone": "+41 44 987 65 43",
"website": "https://www.example.com",
"defaultHourlyRate": 175.00
}
Validierung
Feld | Regeln |
---|---|
companyName | required , string , max:255 |
contactName | nullable , string , max:255 |
careOf | nullable , string , max:255 |
department | nullable , string , max:255 |
street | nullable , string , max:255 |
zip | nullable , string , max:255 |
city | nullable , string , max:255 |
country | nullable , string , max:255 |
website | nullable , string , max:255 , url |
phone | nullable , string , max:255 |
email | nullable , email , max:255 |
poBox | nullable , string , max:255 |
defaultHourlyRate | nullable , numeric , min:0 , max:999999.99 |
archived | nullable , boolean |
invoice_address | nullable , string |
number | nullable , integer |
Response
HTTP/1.1 201 Created
Content-Type: application/json
{
"id": 412,
"company_id": 123,
"userId": 456,
"companyName": "Neue Firma AG",
"number": 1002,
"street": "Beispielstrasse 456",
"zip": "8002",
"city": "Zürich",
"country": "Schweiz",
"website": "https://www.example.com",
"phone": "+41 44 987 65 43",
"defaultHourlyRate": 175.00,
"email": "contact@example.com",
"archived": false,
"created_at": "2024-01-15T14:22:00.000000Z",
"updated_at": "2024-01-15T14:22:00.000000Z"
}
Besonderheiten
- Automatische Kundennummer: Wird generiert wenn nicht angegeben
- Hauptkontakt: Bei
contactName
wird automatisch ein Hauptkontakt erstellt
Beispiel
curl -X POST \
-H "Authorization: Bearer 1|abcdef123456789..." \
-H "Content-Type: application/json" \
-d '{
"companyName": "Neue Firma AG",
"contactName": "Anna Beispiel",
"email": "contact@example.com",
"defaultHourlyRate": 175.00
}' \
"https://app.milkee.ch/api/v2/companies/123/customers"
Einzelnen Customer abrufen
GET /companies/{company}/customers/{customer}
Ruft die Details eines spezifischen Customers ab, inklusive aller zugehörigen Kontakte.
Parameter
Parameter | Typ | Beschreibung |
---|---|---|
company | integer | Firmen-ID |
customer | integer | Customer-ID |
Response
Vollständige Customer-Details
Diese Response enthält vollständige Customer-Details mit allen Contact-Objekten, aber keine berechneten Geschäftsmetriken. Für Statistiken verwenden Sie den Statistics-Endpoint.
{
"id": 410,
"company_id": 123,
"userId": 456,
"companyName": "Muster AG",
"number": 1001,
"contactName": null,
"careOf": null,
"poBox": null,
"department": null,
"street": "Beispielstrasse 15",
"zip": "8001",
"city": "Zürich",
"country": "Schweiz",
"website": null,
"phone": null,
"defaultHourlyRate": 150.00,
"email": "max@example.com",
"invoice_address": null,
"archived": false,
"created_at": "2023-06-04T15:23:12.000000Z",
"updated_at": "2025-07-17T10:54:45.000000Z",
"contacts": [
{
"id": 175,
"company_id": 123,
"user_id": 456,
"customer_id": 410,
"name": "Max Muster",
"email": null,
"phone": null,
"greeting": null,
"is_primary": true,
"archived": false,
"import_source": null,
"created_at": "2024-12-04T17:11:06.000000Z",
"updated_at": "2024-12-04T17:11:06.000000Z"
}
]
}
Beispiel
curl -H "Authorization: Bearer 1|abcdef123456789..." \
"https://app.milkee.ch/api/v2/companies/123/customers/410"
Customer aktualisieren
PUT /companies/{company}/customers/{customer}
Aktualisiert einen bestehenden Customer.
Request Body
{
"companyName": "Muster AG (aktualisiert)",
"contactName": "Max Muster",
"defaultHourlyRate": 165.00,
"email": "new-email@example.com"
}
Response
{
"id": 410,
"companyName": "Muster AG (aktualisiert)",
"contactName": "Max Muster",
"defaultHourlyRate": 165.00,
"email": "new-email@example.com",
"updated_at": "2024-01-15T15:45:00.000000Z"
}
Beispiel
curl -X PUT \
-H "Authorization: Bearer 1|abcdef123456789..." \
-H "Content-Type: application/json" \
-d '{
"companyName": "Muster AG (aktualisiert)",
"defaultHourlyRate": 165.00
}' \
"https://app.milkee.ch/api/v2/companies/123/customers/410"
Customer löschen
DELETE /companies/{company}/customers/{customer}
Löscht einen bestehenden Customer unwiderruflich.
Löschbedingungen
Ein Customer kann nur gelöscht werden, wenn:
- Keine Projekte mit dem Customer verknüpft sind
- Keine Rechnungen für den Customer existieren
Andernfalls wird ein 400-Fehler zurückgegeben.
Response
HTTP/1.1 204 No Content
Beispiel
curl -X DELETE \
-H "Authorization: Bearer 1|abcdef123456789..." \
"https://app.milkee.ch/api/v2/companies/123/customers/410"
Kundenstatistiken abrufen
GET /companies/{company}/customers/{customer}/statistics
Ruft detaillierte Statistiken für einen spezifischen Customer ab.
Response
{
"profit": {
"total": 12500.00,
"formatted": "CHF 12,500.00"
},
"income": 15000.00,
"expenses": 2500.00,
"projects_count": 5,
"invoices_count": 12,
"open_times_minutes": 240,
"open_expenses_sum": 450.75
}
Beispiel
curl -H "Authorization: Bearer 1|abcdef123456789..." \
"https://app.milkee.ch/api/v2/companies/123/customers/410/statistics"
Fehlerbehandlung
Häufige Fehler
400 Bad Request - Customer kann nicht gelöscht werden
{
"message": "Kund:in kann nicht gelöscht werden, da noch Projekte vorhanden sind. Lösche diese zuerst oder archiviere den Kunden."
}
422 Validation Error
{
"message": "The given data was invalid.",
"errors": {
"companyName": [
"Name für Kund:in fehlt."
],
"email": [
"E-Mail-Adresse ist nicht gültig."
],
"defaultHourlyRate": [
"Stundensatz muss eine Zahl sein."
]
}
}
Häufige Validierungsfehler:
companyName.required
: Firmenname ist erforderlichemail.email
: Ungültige E-Mail-Adressewebsite.url
: Ungültige Website-URLdefaultHourlyRate.numeric
: Stundensatz muss numerisch seindefaultHourlyRate.min
: Stundensatz muss mindestens 0 seindefaultHourlyRate.max
: Stundensatz darf maximal 999999.99 sein
Filterung und Suche
Nach Archivierungsstatus
# Nur aktive Customers
curl "https://app.milkee.ch/api/v2/companies/123/customers?filter[archived]=false"
# Nur archivierte Customers
curl "https://app.milkee.ch/api/v2/companies/123/customers?filter[archived]=true"
Nach offenen Ausgaben
# Customers mit offenen Ausgaben
curl "https://app.milkee.ch/api/v2/companies/123/customers?filter[expenses]=true"
# Customers ohne offene Ausgaben
curl "https://app.milkee.ch/api/v2/companies/123/customers?filter[expenses]=false"
Nach offenen Zeiten
# Customers mit offenen Zeiten (beliebige Anzahl Minuten)
curl "https://app.milkee.ch/api/v2/companies/123/customers?filter[times]=1"
# Customers mit mehr als 240 Minuten offene Zeit
curl "https://app.milkee.ch/api/v2/companies/123/customers?filter[times]=240"
# Customers ohne offene Zeiten
curl "https://app.milkee.ch/api/v2/companies/123/customers?filter[times]=0"
Best Practices
Customer-Daten-Validierung
Für Dokumentenerstellung benötigte Mindestdaten prüfen:
function validateCustomerForDocuments(customer) {
const requiredFields = ['companyName', 'street', 'zip', 'city'];
return requiredFields.every(field =>
customer[field] && customer[field].trim() !== ''
);
}
Archivierung vs. Löschung
Verwenden Sie Archivierung statt Löschung für bessere Datenintegrität:
// Empfohlen: Archivierung
async function archiveCustomer(customerId) {
return await api.updateCustomer(customerId, {
archived: true
});
}
// Nur bei wirklich nicht mehr benötigten Customers
async function deleteCustomerSafely(customerId) {
try {
await api.deleteCustomer(customerId);
} catch (error) {
if (error.status === 400) {
// Stattdessen archivieren
return await archiveCustomer(customerId);
}
throw error;
}
}
Effiziente Customer-Synchronisation
async function syncCustomers(localCustomers, apiCustomers) {
const updates = [];
for (const localCustomer of localCustomers) {
const apiCustomer = apiCustomers.find(c => c.number === localCustomer.number);
if (!apiCustomer) {
// Neuen Customer erstellen
updates.push(api.createCustomer(localCustomer));
} else if (localCustomer.updated_at > apiCustomer.updated_at) {
// Bestehenden Customer aktualisieren
updates.push(api.updateCustomer(apiCustomer.id, localCustomer));
}
}
return await Promise.all(updates);
}
Nächste Schritte
- Customer Contacts API - Kontakte für Customers verwalten
- Projects API - Customer-Projekte verwalten
- Invoices API - Customer-Rechnungen erstellen
- Code-Beispiele ansehen
- Webhooks einrichten