Jeder Sprint beginnt mit einem Board voller Tickets – und einem Team, das eine perfekt strukturierte Arbeitsumgebung braucht. Für Agenturen, die WordPress-Projekte in zweiwöchigen Zyklen durchführen, bedeutet das, dass sie eine Staging-Umgebung in MyKinsta einrichten, bevor das erste Ticket abgeholt wird.
Das dauert nur ein paar Minuten, aber das ist die Art von Aufgabe, die durch die Maschen fällt, weil sie trivial aussieht.
Mit der Kinsta-API kann dieser Schritt entfallen. Wenn ein Sprint in Jira beginnt, kannst du einen Webhook einrichten, der ein Ereignis in der Middleware auslöst. Dieser liest dann die Nutzdaten, ordnet sie einer Kinsta-Website zu und ruft die API auf, um eine neue Staging-Umgebung zu erstellen.
Warum Agenturen die Bereitstellung von Umgebungen automatisieren sollten
Eine Umgebung zu erstellen, nachdem du einen Sprint geplant hast, bedeutet, MyKinsta zu öffnen, die richtige Kundenwebsite aus einer Liste von Dutzenden zu finden, eine Umgebung zu erstellen und zu benennen und dann zu Jira zurückzukehren. Das ist zwar nicht kompliziert, aber es muss zu einem bestimmten Zeitpunkt geschehen, für jedes Kundenprojekt.
Wenn du das versäumst, beginnt das Team mit der Arbeit in der Umgebung des letzten Sprints. Von da an häufen sich die Änderungen übereinander, und wenn ein Fehler auftritt, gleicht die Isolierung eher der Archäologie als einer Fehlersuche.
Was du brauchst, bevor du anfängst
Um die Kinsta-API mit Jira zu verbinden, brauchst du ein Kinsta-Konto mit mindestens einer WordPress-Website in einer bestehenden Umgebung, ein Jira-Cloud-Konto mit Administratorrechten, um Webhooks zu konfigurieren, und ein lokal installiertes Node.js.
Um dich mit der Kinsta-API zu authentifizieren, navigiere in MyKinsta zu [Unternehmensname] > Unternehmenseinstellungen > API-Schlüssel und klicke auf API-Schlüssel erstellen.

Als Nächstes gibst du dem Schlüssel einen Namen, legst eine Gültigkeitsdauer fest und klickst auf Erzeugen. Der Schlüssel wird nur einmal angezeigt, also notiere ihn dir, bevor du weitermachst.
Du legst ihn in einer .env-Datei im Stammverzeichnis deines Projekts ab, zusammen mit deiner Kinsta-Unternehmens-ID, die du unter Unternehemnseinstellungen > Abrechnungsdetails findest:
KINSTA_API_KEY=your_api_key_here
KINSTA_COMPANY_ID=your_company_id_here
Erhalte deine Jira- und Kinsta-Site-IDs
Du brauchst die Kinsta-Site-ID für jedes Kundenprojekt in der Automatisierung. Das ist eine UUID, die Kinsta bei der Erstellung der Website vergibt. Sie erscheint in der MyKinsta-URL, wenn du eine Website öffnest, oder durch den Aufruf von GET /sites, sobald dein API-Schlüssel eingerichtet ist:
https://my.kinsta.com/sites/details/fbab4927-e354-4044-b226-29ac0fbd20ca/…
Auf der Jira-Website brauchst du die numerische Board-ID für jedes Projekt, das du verbinden willst. Sie erscheint in der URL (hier als 2):
https://your-domain.atlassian.net/jira/software/projects/SCRUM/boards/2
Dies ist derselbe Wert, den Jira in der sprint_started Webhook-Nutzlast als originBoardId enthält. Die Zuordnung von Board-IDs zu Site-IDs findest du in deiner .env-Datei:
BOARD_ID_CLIENT_A=2
SITE_ID_CLIENT_A=fbab4927-e354-4044-b226-29ac0fbd20ca
BOARD_ID_CLIENT_B=5
SITE_ID_CLIENT_B=44b5a6d1-c83f-4b0e-9a1c-2e7dbc903fa1
Außerdem kann Jira für die lokale Entwicklung den localhost nicht direkt erreichen. Mit Ngrok kannst du einen lokalen Port mit einer temporären öffentlichen URL für das Internet freigeben, die du während der Entwicklung als Webhook-Endpunkt verwenden kannst. Sobald du eine Middleware-Adresse im Einsatz hast, kannst du sie ersetzen.
So automatisierst du die Bereitstellung von Sprint-Umgebungen mit Jira und der Kinsta-API
Diese Integration läuft über zwei Systeme. In Jira wird ein Webhook ausgelöst, wenn ein Sprint beginnt, und der Event-Payload wird an deine Middleware übermittelt. Bei Kinsta liest die Middleware die Board-ID aus dem Payload, löst sie mithilfe der Config Map in eine Site-ID auf und ruft die Kinsta-API auf, um eine einfache Staging-Umgebung mit dem Namen des Sprints zu erstellen.
1. Einen Jira-Webhook für Sprint-Ereignisse registrieren
Jira Cloud bietet dir zwei Möglichkeiten, einen Webhook zu registrieren. Die einfachere Option für die meisten Teams ist über die Jira-Benutzeroberfläche. Die Option Einstellungen > System befindet sich im Menü oben rechts:

Wähle dort Erweitert > WebHooks und klicke dann auf Einen WebHook erstellen:

Hier gibst du einen Namen ein, fügst eine Middleware-URL mit angehängtem /sprint ein (eine Dummy-Option reicht vorerst aus) und wählst unter Ereignisse Sprint > gestartet. Dadurch wird ein Admin-Webhook erstellt, der für jedes sprint_started Ereignis in deiner gesamten Jira-Instanz ausgelöst wird.

Die zweite Möglichkeit ist die REST-API, die POST /rest/webhooks/1.0/webhook verwendet. Das funktioniert gut, wenn die Webhook-Registrierung Teil eines Deployment-Skripts ist:
curl -X POST \
https://your-domain.atlassian.net/rest/webhooks/1.0/webhook \
-u [email protected]:your-api-token \
-H 'Content-Type: application/json' \
-d '{
"name": "Sprint provisioning webhook",
"url": "https://your-middleware-url.com/sprint",
"events": ["sprint_started"],
"filters": {},
"excludeBody": false
}'
Durch den Aufruf von PUT /rest/webhooks/1.0/webhook/refresh wird die 30-tägige Ablauffrist für den Webhook verlängert. Wenn Jira sprint_started auslöst, kommt die Nutzlast an deinem Endpunkt als JSON POST mit der folgenden Struktur an:
{
"timestamp": 1705431600000,
"webhookEvent": "sprint_started",
"sprint": {
"id": 15,
"self": "https://your-domain.atlassian.net/rest/agile/1.0/sprint/15",
"state": "active",
"name": "Sprint 12",
"startDate": "2026-02-02T00:00:00.000Z",
"endDate": "2026-02-27T00:00:00.000Z",
"originBoardId": 2,
"goal": "Complete payment processing improvements"
}
}
Die Middleware verwendet sprint.originBoardId, um die Kinsta-Site-ID zu ermitteln, und sprint.name, um die neue Umgebung zu benennen: Jedes sprint_started-Ereignis innerhalb deiner Jira-Instanz erreicht den Endpunkt. Die Board-ID in der Config-Map sorgt dafür, dass die Automatisierung auf das richtige Client-Projekt beschränkt wird und alles andere ignoriert wird.
2. Erstelle den Middleware-Endpunkt
Wenn du den Webhook eingerichtet hast, solltest du als Nächstes ein neues Node.js-Projekt initialisieren und Express.js zusammen mit dotenv installieren:
npm init -y
npm install express dotenv
express kümmert sich um das Routing und das Parsen von Anfragen, während dotenv deine .env-Datei lädt. Du musst app.js erstellen, um den Server einzurichten. Hier ist die vollständige Datei:
// app.js
const express = require('express');
const crypto = require('crypto');
require('dotenv').config();
const app = express();
// Raw body parser on the /sprint route enables HMAC signature verification
app.use('/sprint', express.raw({ type: 'application/json' }));
app.use(express.json());
const KinstaAPIUrl = 'https://api.kinsta.com/v2';
const headers = {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.KINSTA_API_KEY}`
};
// Board ID to Kinsta site ID config map
const siteConfig = {
[process.env.BOARD_ID_CLIENT_A]: process.env.SITE_ID_CLIENT_A,
[process.env.BOARD_ID_CLIENT_B]: process.env.SITE_ID_CLIENT_B,
};
function verifyJiraSignature(req) {
const signature = req.headers['x-hub-signature'];
const secret = process.env.JIRA_WEBHOOK_SECRET;
if (!signature || !secret) return false;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
app.post('/sprint', async (req, res) => {
if (!verifyJiraSignature(req)) {
return res.status(401).json({ message: 'Invalid signature' });
}
const body = JSON.parse(req.body);
const { webhookEvent, sprint } = body;
if (webhookEvent !== 'sprint_started') {
return res.status(200).json({ message: 'Event ignored' });
}
const boardId = String(sprint.originBoardId);
const siteId = siteConfig[boardId];
if (!siteId) {
console.log(`No site configured for board ${boardId}`);
return res.status(200).json({ message: 'Board not mapped' });
}
// Kinsta API calls added in the steps below
res.status(200).json({ message: 'Received' });
});
app.listen(3000, () => console.log('Middleware running on port 3000'));
Um den Endpunkt zu schützen, generierst du während der Webhook-Einrichtung einen geheimen Schlüssel. Jira macht dies während der Einrichtung optional, aber für eine sichere Instanz ist es praktisch unerlässlich.
Endpunkt-Sicherheit
Jira signiert jeden Payload und fügt das Ergebnis als sha256=<hash> in den X-Hub-Signature-Header ein. Du fügst das Geheimnis zu deiner .env-Datei zusammen mit den anderen Anmeldeinformationen hinzu:
JIRA_WEBHOOK_SECRET=your_webhook_secret_here
Die Verifizierungsfunktion befindet sich in app.js und verwendet das in Node eingebaute crypto-Modul. Sie liest die Signatur aus dem Request-Header, berechnet den erwarteten HMAC mit dem rohen Request-Body und vergleicht sie mit timingSafeEqual so, dass Timing-Angriffe verhindert werden. Hier ist der relevante Teil von app.js:
const crypto = require('crypto');
function verifyJiraSignature(req) {
const signature = req.headers['x-hub-signature'];
const secret = process.env.JIRA_WEBHOOK_SECRET;
if (!signature || !secret) return false;
const expected = 'sha256=' crypto
.createHmac('sha256', secret)
.update(req.body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Diese Funktion ist das erste, was innerhalb des POST/Sprint-Routenhandlers aufgerufen wird. Wenn die Überprüfung fehlschlägt, gibt die Middleware sofort 401 zurück und nichts anderes wird ausgeführt:
app.post('/sprint', async (req, res) => {
if (!verifyJiraSignature(req)) {
return res.status(401).json({ message: 'Invalid signature' });
}
const body = JSON.parse(req.body);
// …rest of the handler
});
Die Route verwendet express.raw() auf dem Pfad /sprint, weil verifyJiraSignature es braucht, um den HMAC zu berechnen. Wenn die Verifizierung erfolgreich war, liefert JSON.parse(req.body) das gleiche Ergebnis wie express.json().
3. Authentifizierung mit der Kinsta-API und Abruf von Websiteumgebungen
Alle Anfragen an die Kinsta-API verwenden eine Bearer-Token-Authentifizierung: Die Header-Konstante in app.js verwaltet diese für jede Anfrage in der Anwendung. Die require('dotenv').config()-Zeile am Anfang stellt sicher, dass der Schlüssel aus .env geladen wird, bevor irgendetwas anderes ausgeführt wird, sodass er nie im Quellcode selbst erscheint.
Kinsta verwendet für den Provisioning-Endpunkt keine Site-IDs, sondern Environment-IDs. Deshalb solltest du eine getEnvironmentId-Funktion unterhalb der Header-Konstante hinzufügen:
const getEnvironmentId = async (siteId) => {
const resp = await fetch(
`${KinstaAPIUrl}/sites/${siteId}/environments`,
{ method: 'GET', headers }
);
const data = await resp.json();
return data.site.environments[0].id;
};
Diese Methode ruft GET /sites/{siteId}/environments auf und gibt die ID der ersten (d.h. aktiven) Umgebung in der Antwort zurück. Wenn eine Website mehrere Umgebungen verwendet und du eine bestimmte Umgebung finden willst, musst du den Umgebungsnamen abgleichen, anstatt das erste Ergebnis zu nehmen.
4. Eine einfache Staging-Umgebung mit der Kinsta-API erstellen
Nachdem die Site- und Environment-IDs geklärt sind, ruft die Middleware POST /sites/{siteId}/environments/plain auf, um die Sprint-Umgebung zu erstellen. Dies geschieht über die Funktion createSprintEnvironment unterhalb von getEnvironmentId:
const createSprintEnvironment = async (siteId, sprintName) => {
const resp = await fetch(
`${KinstaAPIUrl}/sites/${siteId}/environments/plain`,
{
method: 'POST',
headers,
body: JSON.stringify({
display_name: sprintName,
is_premium: false
})
}
);
const data = await resp.json();
return data;
};
display_name erscheint in MyKinsta, während die direkte Verwendung von sprint.name aus dem Jira-Payload bedeutet, dass jede Umgebung im Dashboard dem Sprint entspricht, zu dem sie gehört. Das is_premium-Flag bestimmt, ob Kinsta diese Umgebung als Standard- oder Premium-Staging-Umgebung bereitstellt. Wenn du es auf false setzt, wird eine Standardumgebung erstellt.
Wenn die Anfrage Kinsta erreicht, wird 202 Accepted mit einer operation_id anstelle einer fertigen Umgebung zurückgegeben:
{
"operation_id": "environments:add-plain-54fb80af-576c-4fdc-ba4f-b596c83f15a1",
"message": "Adding plain environment in progress",
"status": 202
}
Die async Verarbeitung von Kinsta verhindert, dass ein Anfrage-Thread blockiert wird, während die Bereitstellung abgeschlossen wird. Die operation_id übergibst du an den Endpunkt, um den Fortschritt zu verfolgen. Als Nächstes aktualisierst du die POST /sprint-Route, um beide Funktionen nacheinander aufzurufen:
app.post('/sprint', async (req, res) => {
if (!verifyJiraSignature(req)) {
return res.status(401).json({ message: 'Invalid signature' });
}
const body = JSON.parse(req.body);
const { webhookEvent, sprint } = body;
if (webhookEvent !== 'sprint_started') {
return res.status(200).json({ message: 'Event ignored' });
}
const boardId = String(sprint.originBoardId);
const siteId = siteConfig[boardId];
if (!siteId) {
console.log(`No site configured for board ${boardId}`);
return res.status(200).json({ message: 'Board not mapped' });
}
try {
const envId = await getEnvironmentId(siteId);
const result = await createSprintEnvironment(siteId, sprint.name);
res.status(200).json(result);
} catch (err) {
console.error(err);
res.status(500).json({ message: 'Environment creation failed' });
}
});
Die Verwendung des try-Blocks ist sauberer als die Verwendung mehrerer if-Anweisungen. Die Überprüfung der Jira-Signatur muss jedoch am Anfang der Datei stehen, da sie vor jedem anderen Code ausgeführt werden muss.
5. Abfrage des Vorgangsstatus und Bestätigung der Bereitstellung
Um den Abschluss zu verfolgen, rufst du GET /operations/{operation_id} ab, bis der Status 200 ist, indem du die Funktion pollOperation unterhalb von createSprintEnvironment verwendest:
const pollOperation = async (operationId, intervalMs = 5000, maxAttempts = 12) => {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
await new Promise(resolve => setTimeout(resolve, intervalMs));
const resp = await fetch(
`${KinstaAPIUrl}/operations/${operationId}`,
{ method: 'GET', headers }
);
const data = await resp.json();
if (data.status === 200) {
console.log(`Environment ready: ${operationId}`);
return data;
}
if (data.status >= 400) {
throw new Error(`Operation failed: ${data.message}`);
}
}
throw new Error('Operation timed out after maximum attempts');
};
Die Schleife wartet fünf Sekunden zwischen den einzelnen Versuchen und deckt bis zu einer Minute der Bereitstellungszeit ab. Während 200 den Abschluss signalisiert, zeigt jeder 4xx-Status an, dass die Untersuchung fehlgeschlagen ist.

Wenn du das alles mit node app.js ausführst und einen Sprint in Jira startest, sollte die Umgebung innerhalb von ein oder zwei Minuten in MyKinsta erscheinen.
So bleibt deine Agentur dem Sprint immer einen Schritt voraus
Diese Integration stellt eine saubere, benannte einfache Staging-Umgebung in MyKinsta bereit, sobald ein Sprint in Jira gestartet wird. Der Webhook wird ausgelöst, die Middleware löst die Board-ID in eine Site auf, die Kinsta-API erledigt den Rest und das Team holt seine Tickets in einer Umgebung ab, die bereits auf sie wartet.
Wenn die Middleware bereit ist, in Betrieb zu gehen, ist Sevalla ein einfaches Bereitstellungsziel. Du pusht das Projekt zu einem Git-Provider, verbindest das Repo, fügst die Umgebungsvariablen hinzu und aktualisierst die Jira-Webhook-URL auf die Live-Adresse.
Darüber hinaus ist das Agenturpartnerprogramm von Kinsta ideal für Agenturen, die mehrere Kundenprojekte betreuen. Es bietet dir engagierten Support, Co-Marketing-Möglichkeiten und die Art von Infrastrukturpartnerschaft, die die Automatisierungsschicht unterstützt, die du auf der Kinsta-API aufbaust.