This website uses cookies to ensure you get the best experience.

PayFit and our selected partners use cookies and similar technologies (together “cookies”) that are necessary to present this website, and to ensure you get the best experience of it. All the cookies we use are necessary to make the site function - without them, the site wouldn't work.

See our Cookie Policy to read more about the cookies we set.

You can withdraw and manage your consent at any time, by clicking “Manage cookies” at the bottom of each website page.

Skip to main content
PayFit career site
Engineering · Paris · Fully Remote

Engineering Manager

Join us!

Engineering · Paris · Fully Remote

Engineering Manager

Join us!

Loading application form

Already working at PayFit?

Let’s recruit together and find your next colleague.

export default { async fetch(request, env) { // --- GET debug (facultatif) --- if (request.method === "GET") { return respond(200, { note: "POST here with { question }", workspace: env.DUST_WORKSPACE_ID || null, agent: env.DUST_AGENT_ID || null, try_order: ["https://dust.tt", "https://api.us.dust.tt"], hint: "Use POST with JSON body: { question: '...' }" }); } // --- CORS preflight --- if (request.method === "OPTIONS") { return new Response(null, { status: 204, headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "Content-Type", "Access-Control-Allow-Methods": "POST, OPTIONS" } }); } if (request.method !== "POST") return respond(405, { error: "Method Not Allowed" }); // --- Body JSON --- let body; try { body = await request.json(); } catch { return respond(400, { error: "Body must be JSON. Use Content-Type: application/json." }); } const question = (body?.question ?? "").toString().trim(); if (!question) return respond(400, { error: "Invalid 'question' string" }); const username = (body?.username ?? "candidate").toString(); const timezone = (body?.timezone ?? "Europe/Paris").toString(); // --- ENV --- const wsId = (env.DUST_WORKSPACE_ID || "").trim(); const agent = (env.DUST_AGENT_ID || "").trim(); const apiKey = (env.DUST_API_KEY || "").trim(); if (!apiKey) return respond(500, { error: "Missing DUST_API_KEY env var" }); if (!wsId) return respond(500, { error: "Missing DUST_WORKSPACE_ID env var" }); if (!agent) return respond(500, { error: "Missing DUST_AGENT_ID env var" }); // --- Payload (schéma validé Dust) --- const payload = { title: "Career Bot", blocking: true, visibility: "unlisted", message: { content: question, context: { username, timezone }, mentions: [{ type: "agent", configurationId: agent }] } }; // --- Essais en cascade : global, puis US --- const bases = ["https://dust.tt", "https://api.us.dust.tt"]; const errors = []; for (const base of bases) { const url = `${base}/api/v1/w/${encodeURIComponent(wsId)}/assistant/conversations`; try { const res = await fetch(url, { method: "POST", headers: { "Authorization": `Bearer ${apiKey}`, "Content-Type": "application/json", "Accept": "application/json" }, body: JSON.stringify(payload) }); const text = await res.text(); let data; try { data = JSON.parse(text); } catch { errors.push({ base, status: res.status, kind: "non_json", preview: text.slice(0, 200) }); continue; } if (!res.ok) { errors.push({ base, status: res.status, kind: "dust_error", details: data }); continue; } // --- Extraire la réponse de l’agent --- const contentBlocks = Array.isArray(data?.conversation?.content) ? data.conversation.content : []; let answer = "(Pas de réponse disponible)"; try { const lastThread = contentBlocks[contentBlocks.length - 1] || []; const agentMsg = lastThread.find(m => m?.type === "agent_message"); const raw = agentMsg?.content; if (typeof raw === "string" && raw.trim()) answer = raw.trim(); const tc = agentMsg?.contents?.[0]?.content; if (tc?.type === "text_content" && typeof tc?.value === "string") answer = tc.value.trim(); } catch (_) {} return respond(200, { answer, conversation_id: data?.conversation?.sId ?? null, used_url: url }); } catch (e) { errors.push({ base, kind: "network", detail: e?.message || "network error" }); } } // Tout a échoué return respond(502, { error: "All endpoints failed", attempts: errors }); } }; function respond(status, obj) { return new Response(JSON.stringify(obj), { status, headers: { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", "Cache-Control": "no-store" } }); }