
Poe Api Universal Generator
- 1 installs
- Updated April 11, 2026
- wedsamuel1230/poe-api-universal-generator-skills
Makes universal Poe API requests with a POE_API_KEY for LLM chat plus image, video, and audio generation, including routing, retries, and reproducible outputs.
About
This skill provides one workflow for multimodal Poe API requests spanning LLM chat and image, video, and audio generation. A developer uses it when they have a POE_API_KEY and need a single request pipeline with routing, retries, and reproducibility.
- Unified LLM and media generation via OpenAI-compatible and media endpoints
- Handles routing, retries, and reproducible outputs
Poe Api Universal Generator by the numbers
- 1 all-time installs (skills.sh)
- Ranked #14,102 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Jul 27, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wedsamuel1230/poe-api-universal-generator-skills --skill poe-api-universal-generatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| Last updated | April 11, 2026 |
| Repository | wedsamuel1230/poe-api-universal-generator-skills ↗ |
What it does
Makes universal Poe API requests with a POE_API_KEY for LLM chat plus image, video, and audio generation, including routing, retries, and reproducible outputs.
Files
Poe Universal Request Generator
Overview
This skill provides one workflow for Poe multimodal requests.
It supports:
- LLM requests via OpenAI-compatible Poe endpoints.
- Image generation via direct media endpoint.
- Video generation via direct media endpoint.
- Audio generation via direct media endpoint.
When to Use
Use this skill when:
- You need one Poe API workflow for LLM and media requests.
- You have or can set
POE_API_KEY. - You need request routing by mode:
llm,image,video, oraudio. - You need stable retries and reproducible output records.
Do not use this skill when:
- You do not have API key access.
- The task requires private bot access not supported by Poe API.
Doc Evidence
This skill is aligned with official Poe docs and model API pages:
https://creator.poe.com/docs/external-applications/openai-compatible-apihttps://creator.poe.com/docs/external-applications/external-application-guide?bot_name=Nano-Banana-2https://poe.com/Nano-Banana-2/apihttps://poe.com/Veo-3.1/apihttps://poe.com/Lyria-3/api
Reference files:
- Doc notes
- Models directory
- LLM flows
- Media flows
- Parameter mapping
- Error handling
Prerequisites
1. Create a Poe API key at https://poe.com/api/keys. 2. Set environment variable:
- PowerShell:
$env:POE_API_KEY = "<your_key>"
3. Ensure account has subscription or add-on points for paid model calls. 4. Install dependencies with uv sync from this folder.
Mode Routing
| Mode | Endpoint | Example model |
|---|---|---|
llm | /v1/chat/completions (or /v1/responses) | Claude-Sonnet-4.6 |
image | /v1/images | nano-banana-2 |
video | /v1/videos | veo-3.1 |
audio | /v1/audio | lyria-3 |
Media reliability rule:
- Use
stream=Falsefor image, video, and audio bot calls.
Quickstart
Universal request script:
uv run scripts/poe_request_orchestrator.py --mode image --model nano-banana-2 --prompt "Sleeping fox under aurora, cinematic lighting" --out "outputs/fox.json"Video example:
uv run scripts/poe_request_orchestrator.py --mode video --model veo-3.1 --prompt "A skier in the Alps" --params '{"duration":"6s","resolution":"1080p"}' --out "outputs/video.json"Audio example:
uv run scripts/poe_request_orchestrator.py --mode audio --model lyria-3 --prompt "Ambient synthwave loop" --out "outputs/audio.json"LLM example:
uv run scripts/poe_request_orchestrator.py --mode llm --model Claude-Sonnet-4.6 --prompt "Summarize the latest build status" --out "outputs/llm.json"Backward-compatible image wrapper:
uv run scripts/generate_nano_banana_image.py --prompt "A cat in a hat" --aspect-ratio "4:3" --seed 42 --out "outputs/cat.json"OpenAI-Compatible Notes
If your app already uses OpenAI SDK with Poe base URL:
- Set
base_urltohttps://api.poe.com/v1 - Set
api_keytoPOE_API_KEY - Keep
nfixed to1. - Pass custom bot parameters through
extra_body. - For media bots, prefer
stream=False.
Operational Guardrails
- On 429/503/529, honor retry headers and apply exponential backoff with jitter.
- Log request id headers when available for support diagnostics.
- Never print full API keys in logs.
- Prefer official bots when consuming user-owned API keys.
Output Expectations
- Raw API response should be saved for reproducibility.
- If output URL(s) are returned, download in a separate explicit step if required by your workflow.
- Record mode, prompt, model, and parameter set used for each request.
Troubleshooting
401 authentication_error: invalid or missingPOE_API_KEY.402 insufficient_credits: insufficient subscription/add-on points.404 not_found_error: incorrect endpoint or model id.429 rate_limit_error: throttle and retry with backoff.
Governance Checklist
After major edits to this skill: 1. Run python .agents/skills/skill-creator/scripts/quick_validate.py .agents/skills/poe-api-universal-generator. 2. Run script syntax checks for all files in scripts/. 3. Update lockfile parity if this skill is tracked in skills-lock.json.
Files in This Skill
references/poe-doc-notes.md: high-level evidence notes from official docs.references/models-directory.md: practical model ids by mode.references/llm-flows.md: chat and responses usage patterns.references/media-flows.md: image/video/audio direct endpoint patterns.references/parameter-mapping.md: common custom parameter patterns.references/error-handling.md: retries, error types, and support diagnostics.scripts/poe_request_orchestrator.py: universal route and request helper.scripts/generate_nano_banana_image.py: compatibility wrapper for image-only calls.
__pycache__/
*.pyc
.venv/
outputs/
*.log
MIT License
Copyright (c) 2026 Samuel F.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
[project]
name = "poe-api-universal-generator-skill"
version = "2.0.0"
description = "Universal Poe API skill scripts for llm, image, video, and audio request flows"
requires-python = ">=3.11"
dependencies = [
"requests>=2.31.0",
"openai>=1.30.0",
]
[tool.uv]
package = false
Poe API Universal Generator Skill
This is a agent skills for universal Poe API requests using POE_API_KEY, supporting LLM chat plus image, video, and audio generation with mode-based routing, retries, and reproducible outputs.
Universal Poe API skill package for:
- LLM requests (
/v1/chat/completions,/v1/responses) - Image generation (
/v1/images) - Video generation (
/v1/videos) - Audio generation (
/v1/audio)
Why this package
This skill started as Nano Banana 2 image-only guidance and was expanded into a reusable multimodal Poe workflow package.
Project Structure
SKILL.md- trigger rules and workflow contractreferences/- modality-specific guidance and API constraintsscripts/poe_request_orchestrator.py- universal request builder/senderscripts/generate_nano_banana_image.py- backward-compatible image wrapperpyproject.toml- uv-first dependency managementLICENSE- MIT
Install
Add this agent skill with:
npx skills add https://github.com/wedsamuel1230/poe-api-universal-generatorAfter install
- Review
SKILL.mdfor trigger rules and workflow usage. - Set your Poe API key before running real requests:
export POE_API_KEY="<your_key>"PowerShell:
$env:POE_API_KEY = "<your_key>"Optional setup
If the skill uses Python dependencies, install them with:
uv syncQuick test
Example dry run:
uv run scripts/poe_request_orchestrator.py --mode image --model nano-banana-2 --prompt "A fox in snow" --dry-run --out outputs/image.jsonError Handling
Retryable statuses
429rate limit503temporary service unavailable529overload
Backoff policy
- Respect
Retry-Afterwhen available. - Otherwise use exponential backoff with jitter.
Common error classes
401authentication error402insufficient credits404not found (model or endpoint)
Diagnostics
- Persist raw response body.
- Capture
x-request-idwhen present for support debugging. - Never log full API keys.
LLM Flows
Chat Completions
- Endpoint:
/v1/chat/completions - Base URL:
https://api.poe.com/v1 - Auth:
Authorization: Bearer $POE_API_KEY
Payload shape:
modelmessages- optional
stream - optional
extra_bodyfor custom params
Responses API
- Endpoint:
/v1/responses - Use for built-in reasoning, tools, and multi-turn with
previous_response_id.
Guardrails
- Keep
n=1. - Unsupported fields can be silently ignored; log full request metadata for debugging.
- For custom parameters, prefer
extra_body.
Media Flows
Image
- Endpoint:
/v1/images - Example model:
nano-banana-2 - Use
stream=false.
Video
- Endpoint:
/v1/videos - Example model:
veo-3.1 - Use
stream=false.
Audio
- Endpoint:
/v1/audio - Example model:
lyria-3 - Use
stream=false.
Common request fields
modelprompt- optional
extra_bodyfor custom media parameters
Notes
- If a specific media model requires different endpoint behavior, re-verify from its API page before shipping.
Models Directory
Use these as practical defaults and verify availability before production usage.
| Mode | Model | Source |
|---|---|---|
| LLM | Claude-Sonnet-4.6 | OpenAI-compatible API docs |
| Image | nano-banana-2 | https://poe.com/Nano-Banana-2/api |
| Video | veo-3.1 | https://poe.com/Veo-3.1/api |
| Audio | lyria-3 | https://poe.com/Lyria-3/api |
Notes:
- Poe model catalog evolves quickly. Re-check model pages when adding hardcoded defaults.
- Prefer official bots for user-supplied API keys.
Parameter Mapping
Use extra_body for model- or bot-specific custom parameters.
Image examples
aspect_ratioseed
Video examples
durationresolutionaspect_ratioseed
LLM examples
reasoning_effortthinking_budget
Rules:
- Keep base payload minimal.
- Pass unknown or model-specific tuning keys through
extra_body. - Do not append CLI-style flags directly to prompt text.
Poe Docs Notes for Universal Mode
Verified points
1. Poe supports OpenAI-compatible base URL at https://api.poe.com/v1. 2. Poe model and bot calls are authenticated with POE_API_KEY. 3. Nano Banana 2 has a dedicated API page and sample that uses POST https://api.poe.com/v1/images. 4. Veo-3.1 has a dedicated API page and sample that uses POST https://api.poe.com/v1/videos. 5. Lyria-3 is documented as an audio/music generation bot in Poe model pages and external app docs. 6. External app guide confirms API keys spend the owner account points. 7. External app guide notes rate limits and custom parameter support via parameters and OpenAI-compatible extra_body paths. 8. OpenAI-compatible docs note media bot recommendation: call with stream=False for better reliability. 9. OpenAI-compatible docs confirm LLM paths: /v1/chat/completions and /v1/responses.
Useful links
- https://creator.poe.com/docs/external-applications/openai-compatible-api
- https://creator.poe.com/docs/external-applications/external-application-guide?bot_name=Nano-Banana-2
- https://poe.com/Nano-Banana-2/api
- https://poe.com/Veo-3.1/api
- https://poe.com/Lyria-3/api
- https://poe.com/api/keys
Suggested defaults for this skill
- LLM endpoint:
https://api.poe.com/v1/chat/completions - Responses endpoint:
https://api.poe.com/v1/responses - Image endpoint:
https://api.poe.com/v1/images - Video endpoint:
https://api.poe.com/v1/videos - Audio endpoint:
https://api.poe.com/v1/audio - Example models:
Claude-Sonnet-4.6,nano-banana-2,veo-3.1,lyria-3 - Required env var:
POE_API_KEY - Retry policy: exponential backoff with jitter for 429/503/529
#!/usr/bin/env python3
"""Backward-compatible image wrapper for the universal Poe orchestrator."""
from __future__ import annotations
import argparse
import json
from poe_request_orchestrator import main as orchestrator_main
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Generate image via Poe nano-banana-2")
parser.add_argument("--prompt", required=True, help="Image generation prompt")
parser.add_argument("--out", default="nano_banana_response.json", help="Output JSON file path")
parser.add_argument("--aspect-ratio", dest="aspect_ratio", default=None, help="Optional aspect ratio, e.g. 4:3")
parser.add_argument("--seed", type=int, default=None, help="Optional seed")
parser.add_argument("--retries", type=int, default=4, help="Retry attempts for retryable errors")
parser.add_argument("--timeout", type=int, default=90, help="Request timeout seconds")
parser.add_argument("--dry-run", action="store_true", help="Build payload without sending network request")
return parser.parse_args()
def main() -> int:
args = parse_args()
extra = {}
if args.aspect_ratio:
extra["aspect_ratio"] = args.aspect_ratio
if args.seed is not None:
extra["seed"] = args.seed
argv = [
"--mode",
"image",
"--model",
"nano-banana-2",
"--prompt",
args.prompt,
"--out",
args.out,
"--retries",
str(args.retries),
"--timeout",
str(args.timeout),
]
if extra:
argv.extend(["--params", json.dumps(extra, ensure_ascii=False)])
if args.dry_run:
argv.append("--dry-run")
return orchestrator_main(argv)
if __name__ == "__main__":
raise SystemExit(main())
#!/usr/bin/env python3
"""Universal Poe API request helper for llm/image/video/audio modes.
This script builds and submits Poe API requests with shared retry behavior
and writes reproducible response records to disk.
"""
from __future__ import annotations
import argparse
import json
import os
import random
import time
from dataclasses import dataclass
from pathlib import Path
from typing import Any
import requests
BASE_URL = "https://api.poe.com"
RETRYABLE_STATUS = {429, 503, 529}
SUPPORTED_MODES = {"llm", "image", "video", "audio"}
@dataclass(frozen=True)
class Route:
mode: str
endpoint: str
def resolve_route(mode: str) -> Route:
key = mode.strip().lower()
if key == "llm":
return Route(mode="llm", endpoint="/v1/chat/completions")
if key == "image":
return Route(mode="image", endpoint="/v1/images")
if key == "video":
return Route(mode="video", endpoint="/v1/videos")
if key == "audio":
return Route(mode="audio", endpoint="/v1/audio")
raise ValueError(f"Unsupported mode: {mode}")
def normalize_stream(mode: str, requested: bool) -> bool:
# Poe docs recommend stream=False for media bots.
if mode.lower() in {"image", "video", "audio"}:
return False
return requested
def build_payload(
*,
mode: str,
model: str,
prompt: str,
params: dict[str, Any] | None = None,
stream: bool = False,
) -> dict[str, Any]:
route = resolve_route(mode)
payload: dict[str, Any]
if route.mode == "llm":
payload = {
"model": model,
"messages": [{"role": "user", "content": prompt}],
"stream": normalize_stream(route.mode, stream),
}
else:
payload = {
"model": model,
"prompt": prompt,
}
if params:
payload["extra_body"] = params
return payload
def post_with_retries(
*,
url: str,
headers: dict[str, str],
payload: dict[str, Any],
timeout: int,
retries: int,
) -> requests.Response:
attempt = 0
while True:
attempt += 1
response = requests.post(url, headers=headers, json=payload, timeout=timeout)
if response.status_code not in RETRYABLE_STATUS:
return response
if attempt > retries:
return response
retry_after = response.headers.get("Retry-After")
if retry_after and retry_after.isdigit():
sleep_s = max(1.0, float(retry_after))
else:
base = min(8.0, 0.25 * (2 ** (attempt - 1)))
sleep_s = base + random.uniform(0.0, 0.25)
time.sleep(sleep_s)
def parse_params(raw: str | None) -> dict[str, Any] | None:
if not raw:
return None
parsed = json.loads(raw)
if not isinstance(parsed, dict):
raise ValueError("--params must be a JSON object")
return parsed
def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Universal Poe API request orchestrator")
parser.add_argument("--mode", required=True, choices=sorted(SUPPORTED_MODES), help="Request mode")
parser.add_argument("--model", required=True, help="Poe model or bot id")
parser.add_argument("--prompt", required=True, help="User prompt")
parser.add_argument("--params", default=None, help="Optional JSON object for extra_body")
parser.add_argument("--stream", action="store_true", help="Enable streaming for llm mode")
parser.add_argument("--timeout", type=int, default=90, help="Request timeout seconds")
parser.add_argument("--retries", type=int, default=4, help="Retry attempts for retryable statuses")
parser.add_argument("--out", default="poe_response.json", help="Output JSON file path")
parser.add_argument("--dry-run", action="store_true", help="Build and save payload without sending network request")
return parser.parse_args(argv)
def save_record(path: Path, record: dict[str, Any]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(record, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
def main(argv: list[str] | None = None) -> int:
args = parse_args(argv)
route = resolve_route(args.mode)
params = parse_params(args.params)
payload = build_payload(mode=args.mode, model=args.model, prompt=args.prompt, params=params, stream=args.stream)
output_path = Path(args.out)
if args.dry_run:
save_record(
output_path,
{
"mode": args.mode,
"endpoint": route.endpoint,
"payload": payload,
"dry_run": True,
},
)
print(f"Dry-run payload saved to {output_path}")
return 0
api_key = os.getenv("POE_API_KEY")
if not api_key:
raise SystemExit("Missing POE_API_KEY environment variable")
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
}
url = f"{BASE_URL}{route.endpoint}"
response = post_with_retries(url=url, headers=headers, payload=payload, timeout=args.timeout, retries=args.retries)
try:
body: Any = response.json()
except Exception:
body = {"raw": response.text}
record = {
"mode": args.mode,
"endpoint": route.endpoint,
"status_code": response.status_code,
"model": args.model,
"payload": payload,
"response": body,
"request_id": response.headers.get("x-request-id"),
}
save_record(output_path, record)
if response.ok:
print(f"Saved response to {output_path}")
return 0
print(f"Request failed: status={response.status_code}, saved response to {output_path}")
return 1
if __name__ == "__main__":
raise SystemExit(main())
# Managed primarily via uv/pyproject.toml; kept for compatibility export.
requests>=2.31.0
openai>=1.30.0