Claude-code-plugins-plus together-webhooks-events
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/together-pack/skills/together-webhooks-events" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-together-webhooks-events && rm -rf "$T"
manifest:
plugins/saas-packs/together-pack/skills/together-webhooks-events/SKILL.mdsource content
Together AI Webhooks & Events
Overview
Together AI delivers webhook callbacks for asynchronous operations including fine-tuning jobs, batch inference, and model lifecycle events. Subscribe to events for fine-tune completion, job failures, model deprecation notices, and batch processing status to build automated ML pipelines without polling the jobs API.
Webhook Registration
const response = await fetch("https://api.together.xyz/v1/webhooks", { method: "POST", headers: { "Authorization": `Bearer ${process.env.TOGETHER_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ url: "https://yourapp.com/webhooks/together", events: ["fine_tune.completed", "fine_tune.failed", "model.deprecated", "batch.done"], secret: process.env.TOGETHER_WEBHOOK_SECRET, }), });
Signature Verification
import crypto from "crypto"; import { Request, Response, NextFunction } from "express"; function verifyTogetherSignature(req: Request, res: Response, next: NextFunction) { const signature = req.headers["x-together-signature"] as string; const expected = crypto.createHmac("sha256", process.env.TOGETHER_WEBHOOK_SECRET!) .update(req.body).digest("hex"); if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) { return res.status(401).json({ error: "Invalid signature" }); } next(); }
Event Handler
import express from "express"; const app = express(); app.post("/webhooks/together", express.raw({ type: "application/json" }), verifyTogetherSignature, (req, res) => { const event = JSON.parse(req.body.toString()); res.status(200).json({ received: true }); switch (event.type) { case "fine_tune.completed": deployModel(event.data.fine_tune_id, event.data.model_name); break; case "fine_tune.failed": alertTeam(event.data.fine_tune_id, event.data.error_message); break; case "model.deprecated": migratePipelines(event.data.model_id, event.data.replacement_model); break; case "batch.done": collectResults(event.data.batch_id, event.data.output_url); break; } });
Event Types
| Event | Payload Fields | Use Case |
|---|---|---|
| , , | Auto-deploy fine-tuned model |
| , , | Alert team and retry with adjusted params |
| , , | Migrate inference pipelines proactively |
| , , | Download batch results and update billing |
| , , | Monitor training progress in real time |
Retry & Idempotency
const processed = new Set<string>(); async function handleIdempotent(event: { id: string; type: string; data: any }) { if (processed.has(event.id)) return; await routeEvent(event); processed.add(event.id); if (processed.size > 10_000) { const entries = Array.from(processed); entries.slice(0, entries.length - 10_000).forEach((id) => processed.delete(id)); } }
Error Handling
| Issue | Cause | Fix |
|---|---|---|
| Invalid or expired API key | Rotate key at api.together.xyz |
| Fine-tune stuck | Training data format issues | Validate JSONL before submission |
| Batch timeout | Large batch exceeds time limit | Split into smaller batches |
| Model not found | Deprecated without migration | Check events proactively |
Resources
Next Steps
See
together-security-basics.