service_account_model_not_allowed 403: the key's model allowlist

The 403 says the model, or the operation, is not on the service-account key's allowlist. details.model or details.operation names the value to add or avoid.

4 min readSume
All posts

A service-account key can carry two allowlists, and each has its own 403. service_account_model_not_allowed means the model you asked for is not in the key's allowed models. service_account_operation_not_allowed means the API operation itself is not allowed. The first has details.model; the second has details.operation. Neither can be fixed from the request body, because the policy is part of the key.

How the two differ

The checks run in this order for a paid submit: key status, model, then operation. A model refusal comes first, so you may fix one allowlist and meet the other next.

The two allowlist 403 codes on a service-account key (Sume API source, read 2026-10-05)
Codedetails fieldExample valueWhat to change
service_account_model_not_allowedmodela public model idUse an allowed model, or have the id added to the key
service_account_operation_not_allowedoperationmodel.run:<model id>, jobs.read, video_analyze, video_segment, trending-videos.search, scrapecreators.readUse an allowed operation, or have it added to the key

Aliases are handled

Model ids are compared after alias resolution: a request passes if the id, or its canonical form, is on the list. An operation of the form model.run:<id> is also compared in its canonical form. So the compatibility /v1/models/sume/.../runs routes and the canonical product routes do not by themselves cause a mismatch. See the API reference for the route families.

A common surprise: reading a job

jobs.read is its own operation. A key that may submit but may not read will submit successfully and then fail on GET /v1/jobs/:id. Test the full loop (submit, status, result) with the key in staging before you rely on it. This helper turns the error into an actionable message:

import json

BODY = '{"error": {"code": "service_account_operation_not_allowed", "details": {"operation": "jobs.read"}}}'

def explain(body: dict) -> str:
    e = body["error"]
    d = e.get("details", {})
    if e["code"] == "service_account_model_not_allowed":
        return f"model {d['model']} is not on this key's allowlist"
    if e["code"] == "service_account_operation_not_allowed":
        return f"operation {d['operation']} is not allowed for this key"
    return "other error"

print(explain(json.loads(BODY)))

Find out your allowlist early

A refusal on the first production call is a poor way to learn the policy. Ask the owner of the key for its allowed models and operations when you set up the integration, write them into your config and fail fast in your own code when a feature maps to something outside the list. The public catalog at GET /v1/catalog tells you what exists; the key's policy tells you what this credential may use, and the two are not the same set.

Do not route around it

Retrying the same request cannot succeed, and swapping to a model that is not listed meets the same wall. Ask the owner of the key for the access, or use a key whose policy matches your workload. Other 403 causes, such as insufficient_scope, are covered in the related posts.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume