Anleitung · Schnittstelle (API)

Code-Beispiele: PHP, Python, JavaScript, PowerShell, curl

DSGVO Server & Hosting in DE BSI Allianz für Cybersicherheit BSI Allianz für Cybersicherheit ProHunde ProHunde-Kooperation BVZ Berufsverband zertifizierter Hundetrainer BVZ-Kooperation

Code-Beispiele: PHP, Python, JavaScript, PowerShell, curl

Auf dieser Seite steht derselbe Ablauf in fünf Sprachen: anmelden, Kontakte lesen, filtern, einen Kontakt anlegen und wieder löschen. Vollständige, lauffähige Fassungen liegen unter https://deine-adresse.de/api/beispiele/ — dort auch als ZIP-Paket zum Herunterladen.

In allen Beispielen sind zwei Werte einzutragen:

  • die Adresse, zum Beispiel https://deine-adresse.de/api/v1
  • der Schlüssel aus System → API-Schlüssel

1. curl (Kommandozeile)

Der schnellste Weg zum Ausprobieren. Denk an -g, sobald Filter mit eckigen Klammern vorkommen.

# Was darf mein Schlüssel?
curl -sg -H "Authorization: Bearer $KEY" "$BASE/me"

# Die ersten fünf Kontakte, nach Nachname sortiert
curl -sg -H "Authorization: Bearer $KEY" \
     "$BASE/contacts?per_page=5&sort=lastname&fields=id,lastname,firstname,email"

# Filtern: Nachname enthält "Mül", angelegt seit 2026
curl -sg -H "Authorization: Bearer $KEY" \
     "$BASE/contacts?lastname[like]=Mül&created[gte]=2026-01-01"

# Anlegen
curl -sg -X POST -H "Authorization: Bearer $KEY" \
     -H "Content-Type: application/json" \
     -H "Idempotency-Key: beispiel-001" \
     -d '{"lastname":"Müller","firstname":"Erika","email":"erika@example.de"}' \
     "$BASE/contacts"

# Ändern
curl -sg -X PATCH -H "Authorization: Bearer $KEY" \
     -H "Content-Type: application/json" \
     -d '{"city":"Neustadt"}' \
     "$BASE/contacts/4711"

# Löschen (Papierkorb)
curl -sg -X DELETE -H "Authorization: Bearer $KEY" "$BASE/contacts/4711"

Mit jq wird die Ausgabe lesbar:

curl -sg -H "Authorization: Bearer $KEY" "$BASE/contacts?per_page=3" | jq .

# Nur die Gesamtzahl
curl -sg -H "Authorization: Bearer $KEY" \
     "$BASE/contacts?per_page=1" | jq '.meta.total'

2. PHP

<?php

$BASE = 'https://deine-adresse.de/api/v1';
$KEY  = '3f7c9a2e-4b81-4d6f-9a03-7c5e12f8ab44';

function api(string $method, string $path,
             array $query = [], ?array $body = null): array
{
    global $BASE, $KEY;

    $url = $BASE . $path;
    if ($query) {
        // http_build_query kodiert auch verschachtelte Filter richtig:
        // ['lastname' => ['like' => 'Mül']]  ->  lastname%5Blike%5D=M%C3%BCl
        $url .= '?' . http_build_query($query);
    }

    $headers = ['Authorization: Bearer ' . $KEY, 'Accept: application/json'];
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_TIMEOUT        => 30,
    ]);
    if ($body !== null) {
        $headers[] = 'Content-Type: application/json';
        curl_setopt($ch, CURLOPT_POSTFIELDS,
            json_encode($body, JSON_UNESCAPED_UNICODE));
    }
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    $raw    = curl_exec($ch);
    $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $data   = json_decode((string) $raw, true) ?: [];

    if ($status >= 400) {
        throw new RuntimeException(sprintf('[%d %s] %s',
            $status,
            $data['error']['code']    ?? 'unknown',
            $data['error']['message'] ?? 'Unbekannter Fehler'));
    }
    return $data;
}

// Lesen
$result = api('GET', '/contacts', [
    'per_page' => 5,
    'sort'     => 'lastname',
    'fields'   => 'id,lastname,firstname,email',
]);
foreach ($result['data'] as $contact) {
    printf("#%d  %s, %s\n", $contact['id'],
           $contact['lastname'], $contact['firstname']);
}

// Filtern
$treffer = api('GET', '/contacts', [
    'lastname' => ['like' => 'Mül'],
    'created'  => ['gte'  => '2026-01-01'],
]);
printf("%d Treffer\n", $treffer['meta']['total']);

// Anlegen
$neu = api('POST', '/contacts', [], [
    'lastname'  => 'Müller',
    'firstname' => 'Erika',
    'email'     => 'erika.mueller@example.de',
]);
$id = $neu['data']['id'];

// Ändern und löschen
api('PATCH', '/contacts/' . $id, [], ['city' => 'Neustadt']);
api('DELETE', '/contacts/' . $id);

3. Python

Ohne Fremdbibliotheken — nur die Standardbibliothek.

#!/usr/bin/env python3
import json
import urllib.parse
import urllib.request

BASE = "https://deine-adresse.de/api/v1"
KEY  = "3f7c9a2e-4b81-4d6f-9a03-7c5e12f8ab44"


def encode_query(query):
    """Verschachtelte Filter zur Klammerschreibweise der Schnittstelle."""
    parts = []
    for key, value in query.items():
        if isinstance(value, dict):
            for op, operand in value.items():
                parts.append((f"{key}[{op}]", str(operand)))
        else:
            parts.append((key, str(value)))
    return urllib.parse.urlencode(parts)


def api(method, path, query=None, body=None):
    url = BASE + path
    if query:
        url += "?" + encode_query(query)

    headers = {"Authorization": f"Bearer {KEY}", "Accept": "application/json"}
    data = None
    if body is not None:
        data = json.dumps(body, ensure_ascii=False).encode("utf-8")
        headers["Content-Type"] = "application/json"

    request = urllib.request.Request(url, data=data,
                                     headers=headers, method=method)
    try:
        with urllib.request.urlopen(request, timeout=30) as response:
            raw = response.read().decode("utf-8")
            return json.loads(raw) if raw else {}
    except urllib.error.HTTPError as exc:
        error = json.loads(exc.read().decode("utf-8")).get("error", {})
        raise RuntimeError(
            f"[{exc.code} {error.get('code')}] {error.get('message')}"
        ) from None


# Lesen
result = api("GET", "/contacts", {
    "per_page": 5,
    "sort": "lastname",
    "fields": "id,lastname,firstname,email",
})
for contact in result["data"]:
    print(f"#{contact['id']}  {contact['lastname']}, {contact['firstname']}")

# Filtern
treffer = api("GET", "/contacts", {
    "lastname": {"like": "Mül"},
    "created":  {"gte": "2026-01-01"},
})
print(f"{treffer['meta']['total']} Treffer")

# Anlegen, ändern, löschen
neu = api("POST", "/contacts", body={
    "lastname": "Müller",
    "firstname": "Erika",
    "email": "erika.mueller@example.de",
})
record_id = neu["data"]["id"]
api("PATCH", f"/contacts/{record_id}", body={"city": "Neustadt"})
api("DELETE", f"/contacts/{record_id}")


# Alle Datensätze durchlaufen — Seite für Seite, speicherschonend
def alle(resource, **query):
    page = 1
    while True:
        result = api("GET", f"/{resource}",
                     {**query, "page": page, "per_page": 200})
        for row in result["data"]:
            yield row
        if page >= result["meta"]["pages"]:
            return
        page += 1


for kontakt in alle("contacts", fields="id,lastname"):
    pass  # hier verarbeiten

4. JavaScript (Node.js)

Braucht Node 18 oder neuer — dort ist fetch eingebaut.

const BASE = 'https://deine-adresse.de/api/v1';
const KEY  = '3f7c9a2e-4b81-4d6f-9a03-7c5e12f8ab44';

function buildQuery(query) {
    const params = new URLSearchParams();
    for (const [key, value] of Object.entries(query)) {
        if (value === null || value === undefined) continue;
        if (typeof value === 'object' && !Array.isArray(value)) {
            // Verschachtelte Filter: { lastname: { like: 'Mül' } }
            for (const [op, operand] of Object.entries(value)) {
                params.append(`${key}[${op}]`, String(operand));
            }
        } else {
            params.append(key, String(value));
        }
    }
    const s = params.toString();
    return s ? `?${s}` : '';
}

async function api(method, path, { query = {}, body = null } = {}) {
    const headers = { Authorization: `Bearer ${KEY}`, Accept: 'application/json' };
    const init = { method, headers };

    if (body !== null) {
        headers['Content-Type'] = 'application/json';
        init.body = JSON.stringify(body);
    }

    const response = await fetch(BASE + path + buildQuery(query), init);
    const text = await response.text();
    const data = text ? JSON.parse(text) : {};

    if (!response.ok) {
        const e = data.error ?? {};
        throw new Error(`[${response.status} ${e.code}] ${e.message}`);
    }
    return data;
}

// Lesen
const result = await api('GET', '/contacts', {
    query: { per_page: 5, sort: 'lastname',
             fields: 'id,lastname,firstname,email' },
});
for (const c of result.data) {
    console.log(`#${c.id}  ${c.lastname}, ${c.firstname}`);
}

// Filtern
const treffer = await api('GET', '/contacts', {
    query: { lastname: { like: 'Mül' }, created: { gte: '2026-01-01' } },
});
console.log(`${treffer.meta.total} Treffer`);

// Anlegen, ändern, löschen
const neu = await api('POST', '/contacts', {
    body: { lastname: 'Müller', firstname: 'Erika',
            email: 'erika.mueller@example.de' },
});
const id = neu.data.id;
await api('PATCH', `/contacts/${id}`, { body: { city: 'Neustadt' } });
await api('DELETE', `/contacts/${id}`);

Im Browser läuft derselbe Code — dann muss allerdings deine Adresse unter api.cors.origins freigegeben sein, und der Schlüssel stünde im Seitenquelltext. Für Webseiten deshalb besser einen kleinen eigenen Server dazwischenschalten, der den Schlüssel behält.

5. PowerShell

Läuft unter Windows PowerShell 5.1 und unter PowerShell 7.

$BaseUrl = 'https://deine-adresse.de/api/v1'
$ApiKey  = '3f7c9a2e-4b81-4d6f-9a03-7c5e12f8ab44'

# Windows PowerShell 5.1 spricht standardmäßig noch TLS 1.0 — hier umstellen
if ($PSVersionTable.PSVersion.Major -lt 6) {
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
}

function ConvertTo-PwQuery {
    param([hashtable] $Query)
    if (-not $Query -or $Query.Count -eq 0) { return '' }

    $parts = @()
    foreach ($key in $Query.Keys) {
        $value = $Query[$key]
        if ($value -is [hashtable]) {
            foreach ($op in $value.Keys) {
                $name = [System.Uri]::EscapeDataString("$key[$op]")
                $wert = [System.Uri]::EscapeDataString([string]$value[$op])
                $parts += "$name=$wert"
            }
        } else {
            $name = [System.Uri]::EscapeDataString($key)
            $wert = [System.Uri]::EscapeDataString([string]$value)
            $parts += "$name=$wert"
        }
    }
    return '?' + ($parts -join '&')
}

function Invoke-PwApi {
    param(
        [Parameter(Mandatory)][string] $Path,
        [string]    $Method = 'GET',
        [hashtable] $Query  = @{},
        [object]    $Body   = $null
    )

    $params = @{
        Uri         = $script:BaseUrl.TrimEnd('/') + $Path +
                      (ConvertTo-PwQuery -Query $Query)
        Method      = $Method
        Headers     = @{
            'Authorization' = "Bearer $script:ApiKey"
            'Accept'        = 'application/json'
        }
        TimeoutSec  = 30
        ErrorAction = 'Stop'
    }

    if ($null -ne $Body) {
        # Die Umwandlung nach UTF-8 ist nötig, sonst kommen Umlaute falsch an.
        $json = $Body | ConvertTo-Json -Depth 10 -Compress
        $params['Body']        = [Text.Encoding]::UTF8.GetBytes($json)
        $params['ContentType'] = 'application/json; charset=utf-8'
    }

    Invoke-RestMethod @params
}

# Lesen
$result = Invoke-PwApi -Path '/contacts' -Query @{
    per_page = 5; sort = 'lastname'; fields = 'id,lastname,firstname,email'
}
$result.data | Format-Table -AutoSize id, lastname, firstname, email

# Filtern
$treffer = Invoke-PwApi -Path '/contacts' -Query @{
    lastname = @{ like = 'Mül' }
    created  = @{ gte  = '2026-01-01' }
}
Write-Host "$($treffer.meta.total) Treffer"

# Anlegen, ändern, löschen
$neu = Invoke-PwApi -Path '/contacts' -Method POST -Body @{
    lastname = 'Müller'; firstname = 'Erika'; email = 'erika.mueller@example.de'
}
$id = $neu.data.id
Invoke-PwApi -Path "/contacts/$id" -Method PATCH `
             -Body @{ city = 'Neustadt' } | Out-Null
Invoke-PwApi -Path "/contacts/$id" -Method DELETE | Out-Null

Stolperfalle: PowerShell unterscheidet bei Variablennamen keine Groß- und Kleinschreibung. Eine Variable $raw ist dieselbe wie ein Schalter -Raw — das führt zu schwer auffindbaren Fehlern. Im vollständigen Beispiel ist das entsprechend gelöst.

6. Und in anderen Sprachen?

Die Schnittstelle ist gewöhnliches REST mit JSON. Jede Sprache, die HTTP sprechen kann, kommt damit klar — Java, C#, Go, Ruby, Rust, Swift, ABAP.

Am schnellsten geht es über die Beschreibungsdatei:

curl -sg -H "Authorization: Bearer $KEY" "$BASE/openapi.json" -o petworkers.json

Daraus erzeugen die üblichen Werkzeuge (openapi-generator, NSwag, oapi-codegen) einen fertigen Client in der Sprache deiner Wahl.

Zeit für den Wechsel

Frage noch offen?

Wenn dir in der Anleitung etwas fehlt — schreib uns. Wir nehmen Themen aus Support-Tickets oft sofort als neue Anleitung auf.

DSGVO-konform Server in Deutschland Persönlicher Support