LangChain and LangGraph tools
Give LangChain and LangGraph agents tools that create AI images, video, music and speech with PopNow. Each paid call is quoted in USD and runs only after approval.
langchain-popnow gives LangChain and LangGraph agents tools that create images, videos, music and speech with PopNow models, and tools that list models, collect tasks and check the API balance. One API key covers every model, from Nano Banana and Seedream to MiniMax H3, Kling, Suno and Gemini TTS.
Every paid call is quoted in USD first. A paid tool called without max_usd only returns the price: nothing is created and nothing is charged. The package is open source under the MIT license (GitHub) and built on the official Python SDK.
At a glance
| Package | langchain-popnow on PyPI |
| Install | pip install -U langchain-popnow |
| Requires | Python 3.10 or newer, langchain-core 0.3.15 or newer |
| Key | POPNOW_API_KEY, an sk-popnow- key from the API console |
| Billing | USD from your separate API balance. Paid tools quote first and run only with max_usd |
| Tools | Image, video, music and speech generation, any model by ID, model list, task lookup and balance (full list) |
| Source | github.com/popnow-ai/langchain-popnow |
Set up
Install the package
pip install -U langchain-popnowCreate an API key
Create a key in the API console. Giving your agent a key of its own with a low daily spend cap is a good habit: you can revoke it without touching your other integrations. The API balance starts at $0; add funds in API billing.
Put the key in your environment
The tools read the key from POPNOW_API_KEY:
export POPNOW_API_KEY="sk-popnow-..."You can also pass api_key="sk-popnow-..." to any tool or to PopNowToolkit. POPNOW_BASE_URL overrides the API host (default https://api.popnow.ai).
Quote, then run
Call a paid tool once without max_usd to get the price, then again with max_usd set to that price:
from langchain_popnow import PopNowImageGeneration
tool = PopNowImageGeneration()
# 1. Quote: returns the price, starts nothing.
print(tool.invoke({"prompt": "A small red fox curled up in a teacup, soft morning light"}))
# {"status": "needs_confirmation", "model": "google/nano-banana-2.1/text-to-image", "cost_usd": "0.048", ...}
# 2. Approved: creates the task and waits for it.
print(tool.invoke({"prompt": "A small red fox curled up in a teacup, soft morning light", "max_usd": "0.048"}))
# {"status": "succeeded", "task_id": "...", "cost_usd": "0.048", "outputs": [{"url": "https://...", "uri": "popnow://g/.../0"}], ...}When an agent calls the tool with a ToolCall, the tool returns a ToolMessage whose content is the JSON summary above and whose artifact is the full PopNow task or quote record.
Tools
| Tool class | Tool name | What it does | Default model | Billing |
|---|---|---|---|---|
PopNowImageGeneration | popnow_image_generation | Text to image, or edits the images passed in image_urls | google/nano-banana-2.1/text-to-image (edit: google/nano-banana-2.1/edit) | Paid, quoted first |
PopNowVideoGeneration | popnow_video_generation | Text to video, or animates the picture in image_url | minimax/h3/text-to-video (image: minimax/h3/image-to-video) | Paid, quoted first |
PopNowMusicGeneration | popnow_music_generation | Songs and instrumentals, with optional lyrics | suno/v6/text-to-audio | Paid, quoted first |
PopNowSpeech | popnow_text_to_speech | Text to speech in many voices | google/gemini-3.8-flash-tts/text-to-speech | Paid, quoted first |
PopNowCreateTask | popnow_create_task | Any PopNow model by ID, with that model's own input | Chosen by the agent | Paid, quoted first |
PopNowListModels | popnow_list_models | Model IDs and USD rates; with model, that model's input fields | Free | |
PopNowGetTask | popnow_get_task | Collects the result of a task that is still running | Free | |
PopNowCheckBalance | popnow_check_balance | Available and held API balance in USD | Free |
PopNowToolkit().get_tools() returns all eight with one shared configuration.
The generation tools take the common fields (prompt, aspect_ratio, resolution, duration_seconds, voice_id and so on), an optional model to pick another PopNow model, and extra_input for any field that popnow_list_models lists for that model. Model IDs follow the <maker>/<model>/<task> pattern described in Models.
How approval works
PopNow tasks are asynchronous: quote, create at the approved price, then wait for the result. The tools follow the same flow as the developer MCP server:
- Quote. The agent calls a paid tool without
max_usd. The tool asks PopNow for a quote and returnsstatus: "needs_confirmation"withcost_usd. Nothing is created or held. - Approve. The agent shows the price to the user. After approval it calls the tool again with the same arguments plus
max_usdset to the quotedcost_usd. - Run. If the current quote is within
max_usd, the task is created with that quote locked and the tool waits for the result. If the price went up, the tool returns a newneeds_confirmationand charges nothing.
Results contain signed download URLs, which expire, and a popnow://g/<task>/<n> URI that does not expire and can be passed to another PopNow tool, for example to animate a generated image. A long video may still be running when wait_timeout (default 600 seconds) ends: the tool then returns status: "running" with a task_id, and popnow_get_task collects the result later. Failed or expired tasks release their hold and cost nothing.
Spending guards
Set these on any paid tool or on PopNowToolkit:
| Setting | Effect |
|---|---|
max_usd_per_call="1.00" | Hard ceiling. A quote above it returns status: "over_limit", even if the agent passed a higher max_usd |
auto_approve_usd="0.05" | For unattended pipelines: quotes at or below this amount run without max_usd. The default None means every paid call needs approval |
allow_model_override=False | The agent cannot switch away from the tool's configured model |
The spend caps and model allow-list of the API key, set in the API console, apply as well.
Use with a LangChain agent
from langchain.agents import create_agent
from langchain_popnow import PopNowToolkit
tools = PopNowToolkit(max_usd_per_call="1.00").get_tools()
agent = create_agent(
model="anthropic:claude-sonnet-4-6",
tools=tools,
system_prompt=(
"You create media with PopNow tools. Paid tools return a price first: "
"show it to the user and only call again with max_usd after they approve."
),
)
result = agent.invoke({"messages": [{"role": "user", "content": "Make a 9:16 clip of a vintage car on a coastal road"}]})
print(result["messages"][-1].content)The agent can run on any chat model LangChain supports, including PopNow chat models through the OpenAI-compatible endpoint https://api.popnow.ai/v1.
Use with LangGraph
from langchain.chat_models import init_chat_model
from langgraph.prebuilt import create_react_agent
from langchain_popnow import PopNowToolkit
model = init_chat_model("anthropic:claude-sonnet-4-6")
agent = create_react_agent(model, PopNowToolkit(max_usd_per_call="1.00").get_tools())
for step in agent.stream(
{"messages": [{"role": "user", "content": "Write a short lo-fi track for a cooking video and tell me the price first"}]},
stream_mode="values",
):
step["messages"][-1].pretty_print()create_react_agent still works in LangGraph 1.x; new projects can use langchain.agents.create_agent as shown above. For a hard human approval step, combine the tools with LangChain's HumanInTheLoopMiddleware or a LangGraph interrupt.
More examples
Find a model and its inputs
Listing models is free. With model, the tool returns that model's input fields and prices:
from langchain_popnow import PopNowListModels
PopNowListModels().invoke({"modality": "video", "search": "kling"})
PopNowListModels().invoke({"model": "kling/3.0/image-to-video"})Animate a picture with a chosen model
from langchain_popnow import PopNowVideoGeneration
PopNowVideoGeneration().invoke({
"prompt": "Gentle waves, slow push-in",
"image_url": "https://example.com/beach.jpg",
"model": "kling/3.0/image-to-video",
"duration_seconds": 5,
"max_usd": "0.50",
})Voiceovers without a prompt for every line
A voiceover costs a fraction of a cent, so a pipeline can approve small quotes on its own:
from langchain_popnow import PopNowSpeech
speech = PopNowSpeech(auto_approve_usd="0.02")
speech.invoke({"text": "Welcome back to the channel!", "voice_id": "Kore"})Any model by ID
PopNowCreateTask sends a model's own input, exactly as in Tasks:
from langchain_popnow import PopNowCreateTask
PopNowCreateTask().invoke({
"model": "alibaba/z-image-turbo/text-to-image",
"input": {"prompt": "A paper boat on a puddle, overcast street, photo", "aspect_ratio": "1:1"},
"max_usd": "0.02",
})Every tool also runs asynchronously: await tool.ainvoke(...).
Pricing
Listing models, reading tasks and checking the balance are free. Generation tools charge the model's USD price to your API balance: a task holds its quoted price when it is accepted and settles the actual charge when it finishes. Tasks that fail or expire cost nothing.
popnow_list_models returns each model's USD rates. Every model's price is on Models and on its own model page; the AI price index lists them too. How quotes, holds and refunds work: Billing and quotes.
Common errors
| You see | Why | Fix |
|---|---|---|
needs_confirmation on every call | The agent never sends max_usd | Tell it in the system prompt to show the price and call again with max_usd after approval, or set auto_approve_usd for small amounts |
over_limit | The quote is above max_usd_per_call | Raise the ceiling, or pick a cheaper model or setting |
401 | The key is missing or revoked | Check POPNOW_API_KEY, or pass api_key |
40201 | Not enough API balance for the task's hold | Add funds in API billing |
40202 | The key's spend cap would be exceeded | Raise the cap for this key in the API console |
40301 | The key may not call this model | Add the model to the key's allow-list |
status: "running" | The task outlasted wait_timeout | Call popnow_get_task with the task_id |
The full list is in Errors.
Does it work with LangGraph?
Yes. The tools are standard LangChain tools, so create_react_agent, ToolNode and custom LangGraph graphs can call them. Pair them with a LangGraph interrupt if a person must approve each price.
Can an agent spend my balance without asking?
Not by default. A paid tool called without max_usd only returns a quote. Spending without approval happens only when you set auto_approve_usd, and max_usd_per_call plus the key's spend caps still apply.
Which models can the tools use?
Any image, video or audio model in the catalog. The generation tools have sensible defaults; pass model to pick another one, or use PopNowCreateTask with any model ID. popnow_list_models lists the IDs from inside the agent.
Is there a JavaScript version?
For TypeScript and JavaScript, use the Vercel AI SDK provider or the JavaScript SDK.
Related
Vercel AI SDK provider
generateImage, generateSpeech, transcribe and chat models in TypeScript.
MCP server for developers
The same quote-and-approve flow for Claude Code, Cursor and Codex.
Billing and quotes
How a task holds, settles and refunds USD.
langchain-popnow on GitHub
Source, issues and the changelog.
Saved recipes and skills
Run saved recipes and workflows through the API or MCP. Quote and approve a USD budget, follow each step, and resume paused runs with the original API key.
AI SDK
Use PopNow models with the Vercel AI SDK 7. generateImage for text to image and image editing, generateSpeech, transcribe and chat models, billed in USD with one API key.

