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.md
source 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

EventPayload FieldsUse Case
fine_tune.completed
fine_tune_id
,
model_name
,
eval_loss
Auto-deploy fine-tuned model
fine_tune.failed
fine_tune_id
,
error_message
,
step
Alert team and retry with adjusted params
model.deprecated
model_id
,
replacement_model
,
sunset_date
Migrate inference pipelines proactively
batch.done
batch_id
,
output_url
,
total_tokens
Download batch results and update billing
fine_tune.checkpoint
fine_tune_id
,
step
,
loss
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

IssueCauseFix
401 Unauthorized
Invalid or expired API keyRotate key at api.together.xyz
Fine-tune stuckTraining data format issuesValidate JSONL before submission
Batch timeoutLarge batch exceeds time limitSplit into smaller batches
Model not foundDeprecated without migrationCheck
model.deprecated
events proactively

Resources

Next Steps

See

together-security-basics
.