HomeDocsAPI

REST API v1

Integriere time2invoice mit deiner Buchhaltungssoftware, Automatisierungs-Tools oder eigenen Anwendungen. Die API gibt dir vollen Zugriff auf Rechnungen, Kunden, Zeiterfassung und EÜR-Berichte.

https://good-roadrunner-663.convex.site/api/v1/
Nur Pro-Plan

Authentifizierung

Alle API-Anfragen müssen mit einem API-Key authentifiziert werden. Erstelle einen Key unter Einstellungen → API-Zugang.

Sende den Key im Authorization-Header:

curl
curl -H "Authorization: Bearer t2i_deinApiKey..." \
  https://good-roadrunner-663.convex.site/api/v1/invoices
JavaScript (fetch)
const response = await fetch("https://good-roadrunner-663.convex.site/api/v1/invoices", {
  headers: {
    "Authorization": "Bearer t2i_deinApiKey...",
    "Content-Type": "application/json"
  }
});

const { data, meta, error } = await response.json();

⚠️ Sicherheitshinweis: API-Keys haben vollen Zugriff auf deinen Account. Teile sie niemals öffentlich und verwende sie nur in Server-seitigem Code, niemals im Frontend.

Rate Limiting

Die API erlaubt 100 Anfragen pro Minute pro API-Key. Bei Überschreitung erhältst du einen 429-Status.

HeaderBeschreibung
X-RateLimit-LimitMaximale Anfragen pro Fenster (100)
X-RateLimit-RemainingVerbleibende Anfragen
Retry-AfterSekunden bis zum nächsten Fenster

Response-Format

Alle Antworten folgen einem konsistenten JSON-Format:

Erfolg
{
  "data": { ... },
  "meta": { "total": 42 },
  "error": null
}
Fehler
{
  "data": null,
  "meta": null,
  "error": "Invalid or expired API key. Pro plan required."
}

Invoices (Rechnungen)

GET/api/v1/invoices

Alle Rechnungen auflisten. Optional nach Status filtern.

Query-Parameter

statusstring"draft" | "sent" | "paid"

Response

{
  "data": [
    {
      "_id": "jd7x...",
      "invoiceNumber": "FR-2026-001",
      "customerId": "k3f9...",
      "invoiceDate": 1735689600000,
      "netAmount": 2400,
      "status": "sent",
      "activityType": "freiberuflich",
      "taxRate": 0,
      "taxAmount": 0,
      "grossAmount": 2400,
      "createdAt": 1735689600000
    }
  ],
  "meta": { "total": 1 },
  "error": null
}
POST/api/v1/invoices

Neue Rechnung erstellen (Status: draft).

Request Body (JSON)

customerIdstringrequiredKunden-ID
invoiceNumberstringrequiredz.B. "FR-2026-002"
invoiceDatenumberrequiredUnix-Timestamp (ms)
periodStartnumberrequiredLeistungszeitraum Start
periodEndnumberrequiredLeistungszeitraum Ende
netAmountnumberrequiredNettobetrag in Euro
notesstringAnmerkungen
taxRatenumberUSt-Satz (0 = Kleinunternehmer)
taxAmountnumberUSt-Betrag
grossAmountnumberBruttobetrag
activityTypestring"freiberuflich" | "gewerblich"

Response

{
  "data": { "id": "jd7x..." },
  "meta": { "created": true },
  "error": null
}

Customers (Kunden)

GET/api/v1/customers

Alle aktiven Kunden auflisten.

Response

{
  "data": [
    {
      "_id": "k3f9...",
      "name": "Acme GmbH",
      "email": "info@acme.de",
      "address": "Musterstr. 1, 10115 Berlin",
      "hourlyRate": 90,
      "isActive": true,
      "activityType": "freiberuflich"
    }
  ],
  "meta": { "total": 1 },
  "error": null
}
POST/api/v1/customers

Neuen Kunden erstellen.

Request Body (JSON)

namestringrequiredKundenname
hourlyRatenumberrequiredStundensatz in Euro
emailstringE-Mail-Adresse
addressstringAnschrift
taxNumberstringSteuernummer des Kunden
ustIdstringUSt-IdNr. des Kunden
activityTypestring"freiberuflich" | "gewerblich"

Response

{
  "data": { "id": "k3f9..." },
  "meta": { "created": true },
  "error": null
}

Time Entries (Zeiteinträge)

GET/api/v1/time-entries

Zeiteinträge auflisten. Optional nach Zeitraum filtern.

Query-Parameter

fromstringStartdatum (ISO 8601, z.B. 2026-01-01)
tostringEnddatum (ISO 8601)

Response

{
  "data": [
    {
      "_id": "te42...",
      "projectId": "p1x7...",
      "customerId": "k3f9...",
      "startTime": 1735689600000,
      "endTime": 1735700400000,
      "durationMinutes": 180,
      "description": "UI-Entwicklung Login-Page",
      "isRunning": false
    }
  ],
  "meta": { "total": 1 },
  "error": null
}
POST/api/v1/time-entries

Neuen Zeiteintrag erstellen (abgeschlossen, kein laufender Timer).

Request Body (JSON)

projectIdstringrequiredProjekt-ID
customerIdstringrequiredKunden-ID
startTimenumberrequiredStartzeit (Unix-Timestamp ms)
endTimenumberrequiredEndzeit (Unix-Timestamp ms)
descriptionstringBeschreibung der Tätigkeit

Response

{
  "data": { "id": "te42..." },
  "meta": { "created": true },
  "error": null
}

Projects (Projekte)

GET/api/v1/projects

Alle aktiven Projekte auflisten.

Response

{
  "data": [
    {
      "_id": "p1x7...",
      "name": "Website Redesign",
      "customerId": "k3f9...",
      "color": "#3b82f6",
      "isActive": true,
      "activityType": "freiberuflich"
    }
  ],
  "meta": { "total": 1 },
  "error": null
}

Reports (Berichte)

GET/api/v1/reports/eur

EÜR-Daten (Einnahme-Überschuss-Rechnung) für ein Jahr abrufen. Getrennt nach freiberuflich/gewerblich.

Query-Parameter

yearnumberJahr (z.B. 2026). Default: aktuelles Jahr

Response

{
  "data": {
    "year": 2026,
    "income": {
      "total": 48000,
      "byType": {
        "freiberuflich": 36000,
        "gewerblich": 12000
      },
      "invoiceCount": 24
    },
    "expenses": {
      "total": 8500,
      "count": 42
    },
    "profit": 39500
  },
  "meta": null,
  "error": null
}

Webhooks

Registriere Webhook-Endpoints unter Einstellungen → API-Zugang um Echtzeit-Benachrichtigungen zu erhalten.

Verfügbare Events

EventBeschreibungAuslöser
invoice.createdNeue Rechnung erstelltRechnung wird als Draft angelegt
invoice.sentRechnung versendetStatus wechselt zu 'sent'
invoice.paidZahlung eingegangenStatus wechselt zu 'paid'
customer.createdNeuer Kunde angelegtKunde wird erstellt
expense.createdNeue Ausgabe erfasstAusgabe wird erstellt

Payload-Format

Webhook Payload
POST https://dein-server.de/webhook
Content-Type: application/json
X-T2I-Event: invoice.created
X-T2I-Signature: a1b2c3d4e5f6...

{
  "event": "invoice.created",
  "timestamp": "2026-01-15T10:30:00.000Z",
  "data": {
    "id": "jd7x...",
    "invoiceNumber": "FR-2026-003",
    "netAmount": 1800
  }
}

Signatur-Verifizierung

Jeder Webhook-Request enthält einen X-T2I-Signature-Header mit einer HMAC-SHA256 Signatur des Request-Bodys, erstellt mit deinem Webhook-Secret.

Node.js — Signatur verifizieren
import crypto from "crypto";

function verifyWebhookSignature(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body, "utf-8")
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(signature, "hex"),
    Buffer.from(expected, "hex")
  );
}

// In deinem Webhook-Handler:
app.post("/webhook", (req, res) => {
  const signature = req.headers["x-t2i-signature"];
  const isValid = verifyWebhookSignature(
    JSON.stringify(req.body),
    signature,
    "whsec_deinSecret..."
  );

  if (!isValid) {
    return res.status(401).send("Invalid signature");
  }

  const { event, data } = req.body;
  console.log(`Event: ${event}`, data);
  res.status(200).send("OK");
});

Fehlerbehandlung

StatusBedeutungLösung
400Ungültige AnfragePrüfe die Request-Parameter und den JSON-Body
401Nicht authentifiziertAuthorization-Header mit gültigem API-Key senden
403Zugriff verweigertAPI-Key ist abgelaufen oder Pro-Plan erforderlich
429Rate Limit überschrittenWarte und versuche es erneut (siehe Retry-After Header)
500ServerfehlerVersuche es erneut. Bei Wiederholung: Support kontaktieren

🚀 Quick Start

Komplett-Beispiel: Alle Rechnungen abrufen und den Gesamtumsatz berechnen.

JavaScript — Umsatz berechnen
const API_KEY = "t2i_deinApiKey...";
const BASE = "https://good-roadrunner-663.convex.site/api/v1";

async function getTotalRevenue() {
  const res = await fetch(`${BASE}/invoices?status=paid`, {
    headers: { "Authorization": `Bearer ${API_KEY}` }
  });

  const { data, error } = await res.json();
  if (error) throw new Error(error);

  const total = data.reduce((sum, inv) => sum + inv.netAmount, 0);
  console.log(`Gesamtumsatz (bezahlt): ${total.toFixed(2)} €`);
  console.log(`Anzahl Rechnungen: ${data.length}`);
  return total;
}

getTotalRevenue();

Fragen zur API? Schreib uns an support@time2invoice.de