Documentation

One policy surface. Real-time or batch.

PromptGuard screens text and MediaGuard screens images against policies you define. Use scalar checks in a request path or asynchronous batches for bulk moderation and backfills. Python SDK aetherlab 0.5.0, REST underneath, x-api-key auth.

01

Scalar quickstart

Install the SDK (Python 3.9+), set your API key, and screen your first output. Keys are issued per environment at app.aetherlab.co.

shell
pip install aetherlab
export AETHERLAB_API_KEY="your-api-key"
quickstart.py
from aetherlab import AetherLabClient

client = AetherLabClient()  # reads AETHERLAB_API_KEY

# An AI response you want screened before it ships
ai_response = "Invest all your money in crypto! Guaranteed 10x returns!"

result = client.check_prompt(
    ai_response,
    blacklisted_keywords=["guaranteed returns", "financial advice"],
)

print(result.compliance_status)  # "Non-Compliant"
print(result.is_compliant)       # False
print(result.avg_threat_level)   # probability of policy violation
print(result.rationale)          # why it was flagged

At least one policy is required per check: configure standing policies in Policy Controls at app.aetherlab.co, or pass whitelisted_keywords / blacklisted_keywords per request.

async
import asyncio
from aetherlab import AsyncAetherLabClient

async def main():
    async with AsyncAetherLabClient() as client:
        result = await client.check_prompt(
            "Hello, how can I help you today?",
            blacklisted_keywords=["violence", "weapons"],
        )
        print(result.compliance_status)  # "Compliant"

asyncio.run(main())
02

Batch quickstart

Batches run on AetherLab's servers after submission, so your process does not need to stay open. The recommended guardrail-specific routes infer the endpoint and execution window: send prompt strings or media URL/file-ID strings in items, with policy values shared by the batch in settings.

PromptGuard · recommended
curl -sS -X POST https://api.aetherlab.co/v1/guardrails/prompt/batches \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      "Guaranteed returns with no risk.",
      "Your funds may lose value."
    ],
    "settings": {
      "blacklisted_keyword": "guaranteed returns",
      "reasoning_mode": "medium",
      "risk_tolerance": "medium"
    }
  }'
MediaGuard · recommended
curl -sS -X POST https://api.aetherlab.co/v1/guardrails/media/batches \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      "https://assets.example.com/campaign.png",
      "50fd109f-4c3a-42b7-92be-14c1d8f89111"
    ],
    "settings": {
      "blacklisted_keyword": "regulated product claim",
      "reasoning_mode": "medium"
    }
  }'
Required follow-up · poll, then retrieve verdicts
# Copy the "id" from the creation response.
BATCH_ID="33333333-3333-4333-8333-333333333333"

# Poll every 5–10 seconds until status is completed, failed, cancelled, or expired.
curl -sS "https://api.aetherlab.co/v1/batches/${BATCH_ID}" \
  -H "x-api-key: YOUR_API_KEY"

# A terminal status describes processing. Fetch results for item-level verdicts.
curl -sS "https://api.aetherlab.co/v1/batches/${BATCH_ID}/results" \
  -H "x-api-key: YOUR_API_KEY"

The creation response is queued job metadata, not compliance verdicts. Small batches commonly complete in about 1–2 minutes; larger batches can take longer depending on item count, reasoning mode, and service load. The supported 24-hour processing window is not a completion-time SLA.

custom_id and Idempotency-Key are optional advanced controls on these routes. AetherLab generates correlation IDs when omitted. Supply your own item IDs when results must join directly to customer records; supply one concrete stable retry key before the first POST only when an uncertain submission may need to be replayed.

SDK helpers

prompt_batch.py
from aetherlab import AetherLabClient

client = AetherLabClient()
batch = client.check_prompt_batch(
    [
        "Guaranteed returns with no risk.",
        "Your funds may lose value.",
    ],
    blacklisted_keywords=["guaranteed returns"],
)

batch = client.wait_for_batch(batch)  # polls the server in v1
for item in client.iter_batch_results(batch.id):
    print(item.custom_id, item.result or item.error)
JSONL input
uploaded = client.upload_file(
    "requests.jsonl",
    purpose="batch",
)
batch = client.create_batch(
    "/v1/guardrails/prompt",
    idempotency_key="docs-jsonl-backfill-001",
    input_file_id=uploaded.id,
    completion_window="24h",
)
MediaGuard batch
media_file = client.upload_file(
    "campaign.png",
    purpose="guardrail_media",
)
media_batch = client.check_media_batch(
    [
        {"custom_id": "media-url-001",
         "url": "https://assets.example.com/campaign.png"},
        {"custom_id": "media-file-001",
         "file_id": media_file.id},
    ],
    idempotency_key="docs-media-review-001",
    blacklisted_keywords=["regulated product claim"],
)
async client
from aetherlab import AsyncAetherLabClient

async with AsyncAetherLabClient() as client:
    batch = await client.check_prompt_batch(
        prompts,
        idempotency_key="docs-async-backfill-001",
        blacklisted_keywords=["guaranteed returns"],
    )
    batch = await client.wait_for_batch(batch)
    page = await client.get_batch_results(batch.id)
    for item in page.items:
        print(item.custom_id, item.result or item.error)

SDK 0.5.0 exposes matching sync and async resource methods on AetherLabClient and AsyncAetherLabClient: upload_file, create_batch, check_prompt_batch, check_media_batch, list_batches, retrieve_batch, wait_for_batch, get_batch_results, cancel_batch, and delete_batch. The lower-level generic create method requires an idempotency key; the recommended REST routes above do not.

03

Authentication

All requests authenticate with an x-api-key header against https://api.aetherlab.co. The SDK reads AETHERLAB_API_KEY from the environment, or accepts api_key= explicitly.

  • ·Never expose keys in client-side code; keep them in server environment variables.
  • ·Use separate keys for development and production, and rotate them periodically.
04

PromptGuard · POST /v1/guardrails/prompt

Screens text against your guardrail policies and returns a compliance verdict with a threat level, confidence, and rationale. This endpoint backs the SDK's check_prompt().

ParameterTypeRequiredDescription
user_promptstringYesThe text to check
whitelisted_keywordstringNo*Comma-separated topics/keywords that are allowed
blacklisted_keywordstringNo*Comma-separated topics/keywords that are not allowed
reasoning_modestringNoReasoning effort: low (default), medium, or high
risk_tolerancestringNolow, medium, or high
environmentstringNoEnvironment tag (default: production)

* At least one policy is required: standing policies from Policy Controls, or a whitelist/blacklist sent with the request. Otherwise the API returns ERR_0202.

curl
curl -X POST https://api.aetherlab.co/v1/guardrails/prompt \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "user_prompt": "Invest all your money in crypto! Guaranteed 10x returns!",
    "blacklisted_keyword": "guaranteed returns,financial advice"
  }'

The SDK method test_prompt() is a deprecated 0.3.x alias. Use check_prompt() in new integrations.

05

MediaGuard · POST /v1/guardrails/media

Screens an image against your guardrail policies. Accepts multipart form data with input_type set to file, url, or base64, plus the same policy and tuning fields as the prompt endpoint. Backs the SDK's check_media() and returns the same response shape.

python
result = client.check_media(
    "photo.png",
    input_type="file",
    blacklisted_keywords=["violence"],
)
print(result.compliance_status)
06

Batch resources

Batch support is additive: the scalar endpoints above remain available. Use the guardrail-specific routes for normal inline submissions. The generic resource API remains available for provider-compatible envelopes and uploaded JSONL workflows.

MethodPathPurpose
POST/v1/filesUpload JSONL (purpose=batch) or media (purpose=guardrail_media)
POST/v1/guardrails/prompt/batchesRecommended prompt strings plus shared settings
POST/v1/guardrails/media/batchesRecommended media URL/file-ID strings plus shared settings
POST/v1/batchesAdvanced generic inline or JSONL creation
GET/v1/batchesList batches
GET/v1/batches/{batch_id}Poll batch status and item counts
GET/v1/batches/{batch_id}/resultsRead item results
POST/v1/batches/{batch_id}/cancelRequest cancellation
DELETE/v1/batches/{batch_id}Delete a terminal batch resource

Advanced provider-compatible creation

POST /v1/batches preserves the generic envelope for interoperability. Unlike the recommended routes, it requires an endpoint, the 24-hour completion window, batch-unique correlation IDs, and a concrete idempotency key.

advanced · generic inline
curl -X POST https://api.aetherlab.co/v1/batches \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Idempotency-Key: prompt-backfill-001" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint": "/v1/guardrails/prompt",
    "completion_window": "24h",
    "requests": [
      {
        "custom_id": "prompt-001",
        "method": "POST",
        "url": "/v1/guardrails/prompt",
        "body": {
          "user_prompt": "Guaranteed returns with no risk.",
          "blacklisted_keyword": "guaranteed returns"
        }
      }
    ]
  }'
advanced · upload JSONL
curl -X POST https://api.aetherlab.co/v1/files \
  -H "x-api-key: YOUR_API_KEY" \
  -F "purpose=batch" \
  -F "file=@requests.jsonl"

# Then POST /v1/batches with Idempotency-Key and:
# {"endpoint":"/v1/guardrails/prompt",
#  "input_file_id":"FILE_ID","completion_window":"24h"}
one requests.jsonl line
{"custom_id":"prompt-001","method":"POST","url":"/v1/guardrails/prompt","body":{"user_prompt":"Guaranteed returns.","blacklisted_keyword":"guaranteed returns"}}
advanced · MediaGuard inline items
[
  {
    "custom_id": "media-url-001",
    "body": {
      "input_type": "url",
      "image": "https://assets.example.com/campaign.png"
    }
  },
  {
    "custom_id": "media-file-001",
    "body": {
      "input_type": "file",
      "file_id": "MEDIA_FILE_ID"
    }
  }
]
status
curl https://api.aetherlab.co/v1/batches/BATCH_ID \
  -H "x-api-key: YOUR_API_KEY"
results
curl https://api.aetherlab.co/v1/batches/BATCH_ID/results \
  -H "x-api-key: YOUR_API_KEY"
cancel or delete
curl -X POST https://api.aetherlab.co/v1/batches/BATCH_ID/cancel \
  -H "x-api-key: YOUR_API_KEY"

curl -X DELETE https://api.aetherlab.co/v1/batches/BATCH_ID \
  -H "x-api-key: YOUR_API_KEY"
07

Batch semantics, limits & retention

Correlation and order

The recommended routes generate a deterministic custom_id when you omit one; supplied IDs must be unique. The advanced generic API requires them. Results are unordered, so correlate every result by its returned custom_id.

Partial failures

Items are independent. A terminal batch can contain successful and failed items; each result carries its own response or error. Inspect every item instead of treating batch completion as universal success.

Media input

MediaGuard batch items reference an HTTPS media URL or a file ID returned by POST /v1/files. Base64 media is not accepted in batches; scalar check_media remains available for that input type.

Window and polling

v1 supports a 24h completion window and uses status polling. Small batches commonly complete in about 1–2 minutes; larger batches can take longer. Poll every 5–10 seconds with backoff, then fetch results after the status becomes terminal.

Documented service limits

  • Inline: up to 1,000 items and a 10 MiB request body.
  • JSONL: up to 50,000 items and a 200 MiB file.
  • These are accepted-input limits, not throughput, latency, or completion guarantees.
results · correlate by custom_id
{
  "object": "list",
  "batch_id": "BATCH_ID",
  "data": [
    {
      "custom_id": "prompt-001",
      "status": "succeeded",
      "response": {
        "status": 200,
        "message": "Prompt Guard Response",
        "data": {"compliance_status": "Non-Compliant"}
      }
    },
    {
      "custom_id": "prompt-002",
      "status": "failed",
      "error": {
        "message": "This item could not be processed."
      }
    }
  ],
  "has_more": false
}

Batch inputs use encrypted private staging. Results remain available for seven days. Staged media is removed promptly after processing and no later than 24 hours; downstream model-provider retention remains provider-dependent.

08

Scalar responses

Both endpoints return a data object with the verdict. The SDK exposes it as ComplianceResult (compliance_status, is_compliant, avg_threat_level, confidence, rationale, full body as raw).

compliant
{
  "status": 200,
  "message": "Prompt Guard Response",
  "data": {
    "compliance_status": "Compliant",
    "avg_threat_level": 0.0,
    "confidence": 1.0,
    "rationale": "No violating content."
  }
}
non-compliant
{
  "status": 200,
  "message": "Prompt Guard Response",
  "data": {
    "compliance_status": "Non-Compliant",
    "avg_threat_level": 1.0,
    "confidence": 1.0,
    "rationale": "Guaranteed returns violate policy."
  }
}
09

Timing expectations

Every check runs a multi-model compliance jury plus your policy engine: the content is evaluated by several models against your rules, and the verdict is adjudicated, scored, and explained. That is substantially more work per request than a single-classifier moderation ping, and the production medians reflect it: roughly 1.4s for text and 1.8s for images (median, across all reasoning modes).

  • ·Budget ~2 seconds for a synchronous check in the request path; where your flow allows, run the check concurrently with other work.
  • ·reasoning_mode controls the depth/latency trade-off per request. Talk to us about tuning it for latency-sensitive paths.
  • ·The response includes the full verdict, threat level, and rationale in one round trip, so no follow-up call is needed to explain a block.

Those medians describe scalar checks only. Small batches commonly complete in about 1–2 minutes, but batch timing scales with item count, reasoning mode, and service load. Poll every 5–10 seconds with backoff. The documented 24-hour processing window is not a completion-time SLA.

10

Errors

Standard HTTP status codes, plus an error_code field the SDK maps to a typed exception hierarchy (all inherit from AetherLabError).

StatusMeaningSDK exception
200Successn/a
400 · ERR_0200 / ERR_0201Malformed requestInvalidRequestError
400 · ERR_0202No guardrail policy configuredMissingPolicyError
401Invalid or missing API keyAuthenticationError
429Rate limit exceeded (honours Retry-After)RateLimitError
5xxServer error (retried automatically)APIError
Network failureUnreachable after all retriesAPIConnectionError
11

Resources

Ship with guardrails this week.

Start with scalar checks, or submit a batch for bulk moderation and backfills. If you need bespoke policies, image workflows at scale, or an assessment first, that's an email away.

Ask about the Evidence Pack

Leave your email and we'll walk you through what an Evidence Pack contains for your use case: severity-scored findings, business-impact mapping, and the approval record.