Perplexity Decisions API as a publish gate for Sume output
Check a finished Sume Format image with Perplexity's Decisions API before it ships: base64 data URL, one yes/no question, a threshold, and a human-review lane.

You can put a decision model after a Sume Format run: when the run finishes, your receiver downloads the image from primary_output_url, sends it to Perplexity's Decisions API with one yes/no question, and publishes only if the returned probability clears a threshold you choose. Sume does not call Perplexity for you; this is a step in your own code, after the webhook.
The check is independent of the run, which is the point. A Format's output_schema can make the generating agent report a boolean about its own work, but an agent grading itself is weaker evidence than a separate model looking at the file.
What does the Decisions API take and return?
Perplexity's quickstart describes a single endpoint, POST https://api.perplexity.ai/v1/decisions, with Bearer auth and the model pplx-decider-v1-27b. You pass a state and a set of named questions; a noul question answers with a probability of yes between 0 and 1.
| Fact | Value | What it means for a Sume gate |
|---|---|---|
| Image input | PNG, JPEG or WebP as base64 data URLs only | Download the artifact first; an https link is not accepted |
| Questions per request | 1 to 128 | Ask several checks in one call |
| Question types | noul, choice, score | noul is the yes/no gate |
| Rate limit | 10 requests per second per organization | Fine for a webhook receiver; throttle a backfill |
| Price | $0.04 per million input tokens, output free | Verify on the page before you budget |
What does the gate look like in code?
This takes the receipt's primary_output_url, which for an image Format is a durable media.sume.com URL, and returns whether to publish. It refuses to guess when the file type is not one the API lists.
import base64, os, requests
OK_TYPES = {"image/png", "image/jpeg", "image/webp"}
def gate(image_url, question, threshold=0.9):
img = requests.get(image_url, timeout=60)
img.raise_for_status()
kind = img.headers.get("content-type", "").split(";")[0]
if kind not in OK_TYPES:
return "review"
data_url = f"data:{kind};base64," + base64.b64encode(img.content).decode()
body = {
"model": "pplx-decider-v1-27b",
"state": [{"type": "image_url", "image_url": {"url": data_url}}],
"questions": {"ok": {"type": "noul", "instructions": question, "criteria": "Answer yes only if it is clearly true."}},
}
r = requests.post(
"https://api.perplexity.ai/v1/decisions",
json=body,
headers={"Authorization": "Bearer " + os.environ["PERPLEXITY_API_KEY"]},
timeout=60,
)
if r.status_code != 200:
return "review"
p = r.json()["answers"]["ok"]["noul"]
return "publish" if p >= threshold else "review"Where does it sit in the webhook flow?
The gate belongs in the worker that handles the webhook, after the delivery has been acknowledged.
- Verify the signature and answer 2xx first; Sume gives a receiver 10 seconds, so queue the gate instead of running it inline.
- Fetch the receipt if
payloadis null, which happens when the delivery would exceed 1 MiB;error.result_urlpoints to it. - Branch on
outcome. Onlyokhas a usableoutput; ondegradedthere is media but no structured output, so send it straight to review. - Run
gate()onprimary_output_url. Apublishgoes out; anything else goes to a person with the receipt id.
What does this not cover?
The quickstart lists images, not video, so a clip needs a still frame that you extract yourself, for example with ffmpeg, before the call. A single frame cannot vouch for the other 29 seconds. Treat the check as a cheap filter for obvious misses such as a missing logo or the wrong product, not as approval of the whole video.
Every failure path in the function returns review, never publish. A 429 or a 504 from the decision API, a wrong file type and a network error all leave the asset waiting for a person, which is the safe default for an automated pipeline. Pick the threshold by running the gate over assets you have already judged by eye, and keep each question about one visible fact, such as whether the logo appears.
Sources
Related posts
More in Developers
- Pick the cheapest Sume image model for an aspect ratio (Python)
A short Python script that reads GET /v1/images/models, keeps models that list your ratio, reference count and n, then prices them from the endpoint records.
- Pick a video model from GET /v1/videos/models, not a constant
A new video model should not need a redeploy. Filter the Sume catalog by resolution, duration, audio and frame inputs at runtime, and survive a withdrawn model.
- Pocket TTS API: run it yourself or call a hosted TTS API
Kyutai's Pocket TTS installs with pip and serves from localhost. If you want a hosted API with job URLs instead, here is the Sume request and what changes.
- Poll Recast like a queue client: IN_QUEUE to COMPLETED
Sume's status route returns IN_QUEUE, IN_PROGRESS and COMPLETED beside its own statuses, for clients ported from queue APIs. How they map for a Recast job.
Written by Sume