Ale dirèkteman nan kontni an

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 POST ak yon kò JSON, ki voye nan kèk segonn.
  • Reponn ak nenpòt estati 2xx nan 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 id evènman an (li nan antèt JodaPrint-Event-Id tou). 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:

  1. Li okte brit kò a, anvan okenn analiz JSON.
  2. Kalkile HMAC la epi konpare l ak v1 nan tan konstan.
  3. Refize demann lan lè t gen 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.