Webhook
Webhook yo fè sèvè ou konnen lè yon bagay rive: yon travay enprime oswa echwe, yon enprimant pa gen papye ankò, yon aparèy pa sou liy. Webhook yo fè pati plan Business la ak plan ki pi wo yo.
Ajoute yon adrès
Tablo de bò → Devlopè → Webhook → Ajoute adrès la, oswa ak API a (otorizasyon webhooks:write):
curl https://api.jodaprint.dev/v1/webhooks \
-H "Authorization: Bearer $JODAPRINT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://shop.example.com/jodaprint/webhook","events":["job.printed","job.failed"]}'
Repons lan gen sekrè adrès la (whsec_…), ki parèt yon sèl fwa sèlman. Anrejistre l kòm JODAPRINT_WEBHOOK_SECRET.
Nan pwodiksyon, URL la dwe sèvi ak https epi lonje dwèt sou yon adrès piblik. Lis evènman yo ak kontni yo nan Evènman webhook.
Livrezon
- Chak evènman se yon
POSTak yon kò JSON, ki voye nan kèk segonn. - Reponn ak nenpòt estati
2xxnan 10 segonn. Fè travay ki pran tan yo apre ou fin reponn. - Livrezon ki echwe yo eseye ankò apre 1 minit, 5 minit, 30 minit, 2 èdtan, 6 èdtan ak 12 èdtan (anviwon 21 èdtan an tout).
- Yon adrès ki kontinye echwe pandan 3 jou dezaktive; tablo de bò a montre poukisa, epi ou ka aktive l ankò.
- Yon lòt eseyaj gen menm
idevènman an (li nan antètJodaPrint-Event-Idtou). Anrejistre ID ou deja trete yo epi inyore doub yo. - Tablo de bò a montre chak livrezon ak kòd repons li, epi li ka voye yon evènman ankò oswa voye yon evènman
webhook.test.
Verifye siyati a
Chak demann gen yon antèt:
JodaPrint-Signature: t=1758800000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
v1 se HMAC-SHA256 an ekzadesimal de t + "." + raw body, ak sekrè adrès la kòm kle. Pou verifye:
- Li okte brit kò a, anvan okenn analiz JSON.
- Kalkile HMAC la epi konpare l ak
v1nan tan konstan. - Refize demann lan lè
tgen plis pase 300 segonn diferans ak lè pa w (pou evite repetisyon).
Node.js
Ak SDK a:
import express from "express";
import { verifyWebhook } from "@jodaprint/node";
app.post("/jodaprint/webhook", express.raw({ type: "application/json" }), async (req, res) => {
try {
const event = await verifyWebhook(
req.body, // Buffer: the raw body
req.headers["jodaprint-signature"],
process.env.JODAPRINT_WEBHOOK_SECRET!,
);
res.sendStatus(200);
if (event.type === "job.failed") notifyStaff(event.data);
} catch {
res.sendStatus(400);
}
});
San SDK a:
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody, header, secret, toleranceSec = 300) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1 ?? "");
return a.length === b.length && timingSafeEqual(a, b);
}
PHP
<?php
function jodaprint_verify(string $rawBody, string $header, string $secret, int $tolerance = 300): bool {
$parts = [];
foreach (explode(',', $header) as $p) {
[$k, $v] = array_pad(explode('=', $p, 2), 2, '');
$parts[$k] = $v;
}
$t = (int) ($parts['t'] ?? 0);
if ($t === 0 || abs(time() - $t) > $tolerance) {
return false;
}
$expected = hash_hmac('sha256', $t . '.' . $rawBody, $secret);
return hash_equals($expected, $parts['v1'] ?? '');
}
$raw = file_get_contents('php://input');
if (!jodaprint_verify($raw, $_SERVER['HTTP_JODAPRINT_SIGNATURE'] ?? '', getenv('JODAPRINT_WEBHOOK_SECRET'))) {
http_response_code(400);
exit;
}
$event = json_decode($raw, true);
http_response_code(200);
Python
import hashlib, hmac, json, os, time
def jodaprint_verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(",") if "=" in p)
try:
t = int(parts.get("t", "0"))
except ValueError:
return False
if t == 0 or abs(time.time() - t) > tolerance:
return False
expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, parts.get("v1", ""))
# Flask
@app.post("/jodaprint/webhook")
def webhook():
raw = request.get_data()
if not jodaprint_verify(raw, request.headers.get("JodaPrint-Signature", ""), os.environ["JODAPRINT_WEBHOOK_SECRET"]):
return "", 400
event = json.loads(raw)
return "", 200
Chanje sekrè a
Tablo de bò → Webhook → adrès la → Nouvo sekrè kreye yon nouvo sekrè. Mete sèvè ou ajou touswit: depi lè sa a, livrezon yo siyen ak nouvo sekrè a.