popnow 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. popnow-0.1.0/.gitignore +22 -0
  2. popnow-0.1.0/CHANGELOG.md +22 -0
  3. popnow-0.1.0/LICENSE +21 -0
  4. popnow-0.1.0/PKG-INFO +347 -0
  5. popnow-0.1.0/README.md +310 -0
  6. popnow-0.1.0/examples/async_batch.py +33 -0
  7. popnow-0.1.0/examples/generate_image.py +19 -0
  8. popnow-0.1.0/examples/image_to_video.py +31 -0
  9. popnow-0.1.0/examples/quote_and_create.py +37 -0
  10. popnow-0.1.0/examples/save_to_library.py +24 -0
  11. popnow-0.1.0/examples/text_to_speech.py +28 -0
  12. popnow-0.1.0/examples/webhook_receiver.py +40 -0
  13. popnow-0.1.0/pyproject.toml +68 -0
  14. popnow-0.1.0/src/popnow/__init__.py +95 -0
  15. popnow-0.1.0/src/popnow/_base_client.py +296 -0
  16. popnow-0.1.0/src/popnow/_client.py +160 -0
  17. popnow-0.1.0/src/popnow/_exceptions.py +277 -0
  18. popnow-0.1.0/src/popnow/_version.py +1 -0
  19. popnow-0.1.0/src/popnow/py.typed +0 -0
  20. popnow-0.1.0/src/popnow/resources/__init__.py +1 -0
  21. popnow-0.1.0/src/popnow/resources/account.py +54 -0
  22. popnow-0.1.0/src/popnow/resources/assets.py +322 -0
  23. popnow-0.1.0/src/popnow/resources/files.py +324 -0
  24. popnow-0.1.0/src/popnow/resources/generate.py +250 -0
  25. popnow-0.1.0/src/popnow/resources/jobs.py +412 -0
  26. popnow-0.1.0/src/popnow/resources/models.py +103 -0
  27. popnow-0.1.0/src/popnow/types.py +519 -0
  28. popnow-0.1.0/src/popnow/webhooks.py +192 -0
  29. popnow-0.1.0/tests/__init__.py +0 -0
  30. popnow-0.1.0/tests/conftest.py +92 -0
  31. popnow-0.1.0/tests/test_async.py +103 -0
  32. popnow-0.1.0/tests/test_client.py +178 -0
  33. popnow-0.1.0/tests/test_errors.py +128 -0
  34. popnow-0.1.0/tests/test_files_assets.py +197 -0
  35. popnow-0.1.0/tests/test_generate.py +115 -0
  36. popnow-0.1.0/tests/test_jobs.py +233 -0
  37. popnow-0.1.0/tests/test_webhooks.py +139 -0
@@ -0,0 +1,22 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+ .pytest_cache/
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .coverage
14
+ htmlcov/
15
+
16
+ # Editors / OS
17
+ .idea/
18
+ .vscode/
19
+ .DS_Store
20
+
21
+ # Local metadata (not part of the package)
22
+ REPO_META.json
@@ -0,0 +1,22 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
+ [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [0.1.0] - 2026-10-19
8
+
9
+ ### Added
10
+
11
+ - `PopNow` and `AsyncPopNow` clients (`httpx`), configured by `api_key` / `POPNOW_API_KEY`,
12
+ `base_url` / `POPNOW_BASE_URL`, `timeout`, `max_retries`, `language`, `http_client`.
13
+ - `models.list()` / `models.get()`.
14
+ - `jobs.quote()`, `create()` (idempotency key, quote lock, retention, server-side `wait`), `get()`,
15
+ `list()` / `iter()`, `wait()` with back-off, `create_and_wait()`, `retry()`, `purge()`, `download_url()`.
16
+ - `files.upload()` (upload ticket, PUT, commit), `create_upload_url()`, `commit()`, `import_lora()`, `download()`.
17
+ - `assets.*`: list, iterate, get, save (task output, upload, URL), update, delete, usage, characters.
18
+ - `account.balance()` and `account.usage()`.
19
+ - Helpers: `images.generate()` / `edit()`, `videos.generate()`, `audio.speech()` / `music()` / `transcribe()`.
20
+ - Typed exceptions mapped from the error envelope, with `code`, `status_code`, `request_id` and `reason`.
21
+ - Automatic retries for network errors and codes `429`, `500`, `503`, `50301`, honouring `Retry-After`.
22
+ - `popnow.webhooks`: task callback (`X-Webhook-Signature`) and Standard Webhooks endpoint verification.
popnow-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PopNow
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
popnow-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,347 @@
1
+ Metadata-Version: 2.5
2
+ Name: popnow
3
+ Version: 0.1.0
4
+ Summary: Typed Python SDK for the PopNow API: AI video, image, music and speech generation (Kling, Seedance, Wan, Nano Banana, GPT Image, Suno and more).
5
+ Project-URL: Homepage, https://popnow.ai
6
+ Project-URL: Documentation, https://popnow.ai/docs
7
+ Project-URL: API reference, https://popnow.ai/docs/openapi.yaml
8
+ Project-URL: Source, https://github.com/popnow-ai/popnow-python
9
+ Project-URL: Issues, https://github.com/popnow-ai/popnow-python/issues
10
+ Project-URL: Changelog, https://github.com/popnow-ai/popnow-python/blob/main/CHANGELOG.md
11
+ Author: PopNow
12
+ License-Expression: MIT
13
+ License-File: LICENSE
14
+ Keywords: ai-image-generator,ai-music,ai-video-generator,api-client,generative-ai,image-to-video,popnow,sdk,text-to-image,text-to-speech,text-to-video
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: 3.9
22
+ Classifier: Programming Language :: Python :: 3.10
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Topic :: Multimedia :: Graphics
27
+ Classifier: Topic :: Multimedia :: Video
28
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
29
+ Classifier: Typing :: Typed
30
+ Requires-Python: >=3.9
31
+ Requires-Dist: httpx<1,>=0.25
32
+ Provides-Extra: dev
33
+ Requires-Dist: anyio>=3.7; extra == 'dev'
34
+ Requires-Dist: pytest>=7; extra == 'dev'
35
+ Requires-Dist: respx>=0.21; extra == 'dev'
36
+ Description-Content-Type: text/markdown
37
+
38
+ <div align="center">
39
+ <a href="https://popnow.ai">
40
+ <picture>
41
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/popnow-ai/popnow-python/main/assets/popnow-wordmark-light.png">
42
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/popnow-ai/popnow-python/main/assets/popnow-wordmark.png">
43
+ <img alt="PopNow" src="https://raw.githubusercontent.com/popnow-ai/popnow-python/main/assets/popnow-wordmark.png" width="260">
44
+ </picture>
45
+ </a>
46
+
47
+ <h1>PopNow Python SDK: AI Video, Image and Music Generation API</h1>
48
+
49
+ <p><strong>popnow</strong> is a typed Python client for the PopNow API that turns text, images and audio into AI videos, images, music and speech, using the same models, prices and credits as <a href="https://popnow.ai">popnow.ai</a>.</p>
50
+
51
+ <p>
52
+ <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
53
+ <img alt="Python 3.9 to 3.13" src="https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-3776AB.svg?logo=python&logoColor=white">
54
+ <a href="https://github.com/popnow-ai/popnow-python/actions/workflows/tests.yml"><img alt="Tests" src="https://github.com/popnow-ai/popnow-python/actions/workflows/tests.yml/badge.svg"></a>
55
+ <a href="https://popnow.ai"><img alt="Website: popnow.ai" src="https://img.shields.io/badge/site-popnow.ai-ff5a36.svg"></a>
56
+ <a href="https://popnow.ai/docs"><img alt="Docs" src="https://img.shields.io/badge/docs-popnow.ai%2Fdocs-111111.svg"></a>
57
+ </p>
58
+ </div>
59
+
60
+ PopNow is a browser-based AI studio for videos, images and music: image-to-video, text-to-video, AI images, music and speech, one-tap trending video effects and image styles. This SDK wraps its developer API (`https://api.popnow.ai/api/v1`) so you can call Kling, Seedance, Wan, Vidu, MiniMax, Nano Banana, GPT Image, Flux, Suno and more from Python. Credit packs, no subscription; failed runs are refunded. *Make it pop.*
61
+
62
+ - Sync **and** async clients (`PopNow`, `AsyncPopNow`) built on `httpx`, the only dependency.
63
+ - Typed results (`py.typed`) with snake_case attributes, plus the raw JSON on every object.
64
+ - One-line helpers: `client.images.generate()`, `client.videos.generate()`, `client.audio.speech()`.
65
+ - Safe retries: automatic `Idempotency-Key`, back-off on `429` / `500` / `503` honouring `Retry-After`.
66
+ - Local file uploads, asset library, task history, usage, balance and webhook signature verification.
67
+
68
+ ## Quickstart
69
+
70
+ **1. Install** (Python 3.9+):
71
+
72
+ ```bash
73
+ pip install "git+https://github.com/popnow-ai/popnow-python"
74
+ ```
75
+
76
+ A PyPI release is coming; until then, install from GitHub as above (pin a commit or tag with `@<ref>` for reproducible builds).
77
+
78
+ **2. Create an API key** in the [API console](https://popnow.ai/api/console/keys) and export it:
79
+
80
+ ```bash
81
+ export POPNOW_API_KEY="sk-popnow-..."
82
+ ```
83
+
84
+ **3. Generate:**
85
+
86
+ ```python
87
+ from popnow import PopNow
88
+
89
+ client = PopNow() # reads POPNOW_API_KEY
90
+
91
+ task = client.images.generate(
92
+ model="alibaba/z-image-turbo/text-to-image",
93
+ prompt="A small red fox curled up in a teacup, soft morning light",
94
+ )
95
+ print(task.state, task.credits, task.urls[0])
96
+ client.files.download(task.assets[0], "fox.png")
97
+ ```
98
+
99
+ That image costs a couple of credits (1 credit = $0.01). Buy credits on the [pricing page](https://popnow.ai/pricing); API calls and the website share one wallet.
100
+
101
+ ## What you can call
102
+
103
+ | Area | SDK | API endpoint |
104
+ | --- | --- | --- |
105
+ | Models and prices | `client.models.list()`, `client.models.get(id)` | `GET /api/v1/models`, `GET /api/v1/models/{model}` |
106
+ | Price a request | `client.jobs.quote()` | `POST /api/v1/jobs/quote` |
107
+ | Create a task | `client.jobs.create()` | `POST /api/v1/jobs/createTask` |
108
+ | Read / wait | `client.jobs.get()`, `client.jobs.wait()` | `GET /api/v1/jobs/recordInfo` |
109
+ | Task history | `client.jobs.list()`, `client.jobs.iter()` | `GET /api/v1/jobs` |
110
+ | Retry / purge | `client.jobs.retry()`, `client.jobs.purge()` | `POST /api/v1/jobs/retry`, `POST /api/v1/jobs/purge` |
111
+ | Download link | `client.jobs.download_url()` | `POST /api/v1/common/download-url` |
112
+ | Upload a file | `client.files.upload(path)` | `POST /api/v1/common/upload-url`, `PUT`, `POST /api/v1/files/{id}/commit` |
113
+ | Import a LoRA | `client.files.import_lora(url)` | `POST /api/v1/files/import` |
114
+ | Asset library | `client.assets.*` | `/api/v1/assets*` |
115
+ | Balance / usage | `client.account.balance()`, `client.account.usage()` | `GET /api/v1/chat/credit`, `GET /api/v1/usage` |
116
+ | Webhooks | `popnow.webhooks.verify_task_callback()` | `X-Webhook-Signature` header |
117
+
118
+ ### Supported models
119
+
120
+ Model ids look like `<maker>/<model>/<task>`. Some examples; the live list with prices is `client.models.list()` or [popnow.ai/docs/models](https://popnow.ai/docs/models):
121
+
122
+ | Kind | Example model ids |
123
+ | --- | --- |
124
+ | Text-to-image | `alibaba/z-image-turbo/text-to-image`, `google/nano-banana-2.1/text-to-image`, `openai/gpt-image-2/text-to-image`, `black-forest-labs/flux-2-pro/text-to-image`, `bytedance/seedream-5.0-pro/text-to-image` |
125
+ | Image editing | `google/nano-banana-2.1/edit`, `openai/gpt-image-2/edit`, `popnow/background-remover-v1/edit` |
126
+ | Image-to-video | `alibaba/wan-3.0/image-to-video`, `kling/3.0/image-to-video`, `bytedance/seedance-2.0/image-to-video`, `vidu/q3/image-to-video`, `minimax/h3/image-to-video` |
127
+ | Text-to-video | `kling/3.0/text-to-video`, `alibaba/wan-3.0/text-to-video`, `bytedance/seedance-2.0/text-to-video` |
128
+ | Music | `suno/v6/text-to-audio`, `minimax/music-3.0/text-to-audio` |
129
+ | Speech | `google/gemini-3.8-flash-tts/text-to-speech`, `minimax/speech-2.8-hd/text-to-speech` |
130
+ | Transcription | `xai/grok-stt/speech-to-text` |
131
+ | Upscaling | `popnow/image-upscaler-v1/upscale`, `popnow/video-upscaler-v1/upscale` |
132
+
133
+ Every model has its own `input_schema` (`client.models.get(id).input_schema`). Unknown fields are rejected with a `400`, so typos fail fast.
134
+
135
+ ## Usage
136
+
137
+ ### Image to video
138
+
139
+ ```python
140
+ import pathlib
141
+ from popnow import PopNow
142
+
143
+ client = PopNow()
144
+ task = client.videos.generate(
145
+ model="alibaba/wan-3.0/image-to-video",
146
+ image_url=pathlib.Path("photo.jpg"), # a Path is uploaded for you; URLs work too
147
+ prompt="Waves roll in slowly, the camera drifts toward the lighthouse",
148
+ resolution="480p",
149
+ duration_seconds=5,
150
+ timeout=1800,
151
+ )
152
+ client.files.download(task.assets[0], "clip.mp4")
153
+ ```
154
+
155
+ ### Music, speech and transcription
156
+
157
+ ```python
158
+ song = client.audio.music(model="suno/v6/text-to-audio", prompt="Upbeat lo-fi beat for a cooking video", instrumental=True)
159
+ voice = client.audio.speech(model="google/gemini-3.8-flash-tts/text-to-speech", text="Welcome back!", voice_id="Kore")
160
+ transcript = client.audio.transcribe(model="xai/grok-stt/speech-to-text", audio_url="https://example.com/interview.mp3").text
161
+ ```
162
+
163
+ The helpers fill the shared field names (`prompt`, `text`, `image_url`, `image_urls`, `video_url`, `audio_url`, `duration_seconds`, `resolution`, `aspect_ratio`) and pass every other keyword straight into the model `input`. They wait for the result and raise `TaskFailedError` unless the task succeeds.
164
+
165
+ ### Low-level task API
166
+
167
+ ```python
168
+ from popnow import PopNow, new_idempotency_key
169
+
170
+ client = PopNow()
171
+ body = {
172
+ "model": "alibaba/wan-3.0/image-to-video",
173
+ "input": {"image_url": "https://media.popnow.ai/movie/lighthouse.webp", "resolution": "720p", "duration_seconds": 5},
174
+ }
175
+
176
+ quote = client.jobs.quote(**body) # nothing is created or held
177
+ created = client.jobs.create(
178
+ **body,
179
+ idempotency_key=new_idempotency_key(), # reuse it on every retry of this work
180
+ quote_id=quote.quote_id,
181
+ expected_credits=quote.max_credits, # QuoteMismatchError (40901) if the price changed
182
+ callback_url="https://your-app.example.com/hooks/popnow",
183
+ )
184
+ task = client.jobs.wait(created, timeout=1800) # polls with back-off: 2s, 3s, 4.5s ... up to 15s
185
+ if task.is_succeeded:
186
+ print(task.urls)
187
+ else:
188
+ print(task.state, task.error_code, task.error_message)
189
+ ```
190
+
191
+ - `jobs.create(..., wait=60)` holds the connection up to 60 seconds; if the task finishes in time, `created.task` is the full record.
192
+ - `jobs.create_and_wait(model=..., input=...)` combines the server-side wait with polling.
193
+ - Task states: `queued`, `running`, then `succeeded`, `failed` or `expired`. Unknown states count as not final.
194
+ - `output.assets[].url` is a signed link valid for about 20 minutes. Store the `task_id`, not the link.
195
+
196
+ ### Uploads and the asset library
197
+
198
+ ```python
199
+ uploaded = client.files.upload("reference.png") # popnow://f/fil_...
200
+ asset = client.assets.save_upload(uploaded.file_id, name="Product shot") # popnow://a/ast_...
201
+ for a in client.assets.iter(kind="image", sort="recent"):
202
+ print(a.name, a.uri)
203
+ lora = client.files.import_lora("your-name/your-lora-repo", token="hf_...") # for loras[].path
204
+ ```
205
+
206
+ Uploads are temporary; saved assets stay until you delete them. Images up to 10 MiB, video and audio up to 90 MiB (600 seconds), LoRA `.safetensors` up to 2 GiB.
207
+
208
+ ### Async
209
+
210
+ ```python
211
+ import asyncio
212
+ from popnow import AsyncPopNow
213
+
214
+ async def main() -> None:
215
+ async with AsyncPopNow() as client:
216
+ balance = await client.account.balance()
217
+ task = await client.images.generate(model="alibaba/z-image-turbo/text-to-image", prompt="A paper boat")
218
+ print(balance.available_credits, task.urls)
219
+
220
+ asyncio.run(main())
221
+ ```
222
+
223
+ ### Webhooks
224
+
225
+ ```python
226
+ import os
227
+ from popnow import webhooks, WebhookVerificationError
228
+
229
+ def handle(raw_body: bytes, headers: dict) -> int:
230
+ try:
231
+ event = webhooks.verify_task_callback(raw_body, headers, os.environ["POPNOW_WEBHOOK_SECRET"])
232
+ except WebhookVerificationError:
233
+ return 401
234
+ task = webhooks.task_from_event(event) # event["request_id"] is the stable delivery id
235
+ print(task.task_id, task.state)
236
+ return 200
237
+ ```
238
+
239
+ Task callbacks are signed as `base64(HMAC-SHA256(secret, "<taskId>.<timestamp>.<sha256_hex(raw_body)>"))`; timestamps more than five minutes away are rejected. Account endpoints use the Standard Webhooks format: `webhooks.verify_endpoint_event(raw_body, headers, "whsec_...")`. Always verify the raw request bytes.
240
+
241
+ ## Configuration
242
+
243
+ ```python
244
+ client = PopNow(
245
+ api_key="sk-popnow-...", # default: $POPNOW_API_KEY
246
+ base_url="https://api.popnow.ai", # default: $POPNOW_BASE_URL or this
247
+ timeout=60.0, # seconds per request, or an httpx.Timeout
248
+ max_retries=2, # network errors and codes 429, 500, 503, 50301
249
+ language="de", # Accept-Language for error messages
250
+ http_client=None, # bring your own httpx.Client (proxies, mounts)
251
+ )
252
+ ```
253
+
254
+ Keep keys on your server; never ship them in a browser or mobile app.
255
+
256
+ ## Error handling
257
+
258
+ Every error response is `{"code", "msg", "request_id"}`. The SDK raises a typed exception chosen by the business `code`:
259
+
260
+ | Exception | `code` |
261
+ | --- | --- |
262
+ | `BadRequestError` | `400`, `40003`, `40004` |
263
+ | `AuthenticationError` | `401` |
264
+ | `InsufficientCreditsError` / `SpendCapExceededError` (both `PaymentRequiredError`) | `40201` / `40202` |
265
+ | `PermissionDeniedError` | `403`, `40301`, `40302`, `40303`, `40310` |
266
+ | `NotFoundError` | `404` |
267
+ | `ConflictError` / `QuoteMismatchError` | `409` / `40901` |
268
+ | `PayloadTooLargeError` | `413` |
269
+ | `RateLimitError` | `429` (see `err.retry_after`) |
270
+ | `InternalServerError` | `500` |
271
+ | `ServiceUnavailableError` / `ModelUnavailableError` | `503`, `50302` / `50301` |
272
+ | `APIConnectionError` / `APITimeoutError` | no HTTP response |
273
+ | `TaskFailedError` | task ended `failed` or `expired` (see `err.error_code`) |
274
+ | `WaitTimeoutError` | the local wait budget ran out; the task keeps running |
275
+
276
+ All API errors carry `code`, `status_code`, `message`, `request_id` and, for some asset and content errors, `reason` (`data.reason`).
277
+
278
+ ```python
279
+ from popnow import APIError, InsufficientCreditsError, RateLimitError
280
+
281
+ try:
282
+ client.jobs.create(model="kling/3.0/text-to-video", input={"prompt": "A koi pond in the rain"})
283
+ except InsufficientCreditsError:
284
+ print("Top up at https://popnow.ai/pricing")
285
+ except RateLimitError as err:
286
+ print("retry in", err.retry_after, "seconds")
287
+ except APIError as err:
288
+ print(err.code, err.message, err.request_id, err.reason)
289
+ ```
290
+
291
+ Branch on `code` (and `task.error_code`), never on message text. Quote `request_id` when contacting support.
292
+
293
+ ## Examples
294
+
295
+ See [`examples/`](examples): `generate_image.py`, `image_to_video.py`, `text_to_speech.py`, `quote_and_create.py`, `async_batch.py`, `save_to_library.py`, `webhook_receiver.py`.
296
+
297
+ ## FAQ
298
+
299
+ ### How do I generate a video from an image with an API in Python?
300
+
301
+ Call `client.videos.generate(model="alibaba/wan-3.0/image-to-video", image_url=..., prompt=...)`. Pass a public HTTPS URL, a `popnow://` URI, or a `pathlib.Path` to a local photo, which the SDK uploads first. The call waits for the clip and returns the task with a signed download URL.
302
+
303
+ ### How much does the PopNow API cost?
304
+
305
+ The API uses the same credits and prices as popnow.ai: 1 credit = $0.01, bought in credit packs with no subscription. Each model lists its price in `client.models.get(id).credits`, and `client.jobs.quote()` returns the exact amount for one request. Failed and expired tasks release their hold, so they cost nothing.
306
+
307
+ ### How do I retry an AI generation request without being charged twice?
308
+
309
+ Send the same `Idempotency-Key` with every retry of one piece of work. The SDK generates one per call and reuses it across its own automatic retries; pass `idempotency_key=` yourself (for example `order-8814-render-1`) to stay safe across process restarts. Keys are remembered for 24 hours.
310
+
311
+ ### Do I have to poll for results?
312
+
313
+ No. `jobs.wait()` polls with back-off for you, `jobs.create(wait=60)` returns quick results in the same call, and in production you can pass `callback_url` and verify the webhook with `popnow.webhooks.verify_task_callback()`.
314
+
315
+ ### How do I upload a local file to use as a reference image?
316
+
317
+ `client.files.upload("photo.jpg")` asks for an upload ticket, PUTs the bytes and commits them, then returns a `uri` (`popnow://f/fil_...`) for `image_url` or `image_urls`. To keep a file for reuse, save it with `client.assets.save_upload()`.
318
+
319
+ ### Which AI video and image models can I use from Python?
320
+
321
+ Kling, Seedance, Wan, Vidu, MiniMax, Nano Banana, GPT Image, Flux, Seedream, Suno and more. Call `client.models.list(modality="video")` for the live list with availability and prices.
322
+
323
+ ### Is there an async Python client for AI video generation?
324
+
325
+ Yes. `AsyncPopNow` has the same resources and helpers as `PopNow`, with `await`. Combine it with `asyncio.gather` to run many tasks at once within the rate limits.
326
+
327
+ ### Can I use PopNow from an AI assistant instead of code?
328
+
329
+ Yes. PopNow runs a remote MCP server at `https://api.popnow.ai/mcp` with tools for images, video, music, speech and effects. See [popnow.ai/mcp](https://popnow.ai/mcp).
330
+
331
+ ## Links
332
+
333
+ - Website: [popnow.ai](https://popnow.ai)
334
+ - Docs: [popnow.ai/docs](https://popnow.ai/docs)
335
+ - API reference (OpenAPI): [popnow.ai/docs/openapi.yaml](https://popnow.ai/docs/openapi.yaml)
336
+ - Pricing: [popnow.ai/pricing](https://popnow.ai/pricing)
337
+ - MCP server: [popnow.ai/mcp](https://popnow.ai/mcp)
338
+ - llms.txt: [popnow.ai/llms.txt](https://popnow.ai/llms.txt)
339
+ - Other PopNow repos: [popnow-mcp](https://github.com/popnow-ai/popnow-mcp), [popnow-skills](https://github.com/popnow-ai/popnow-skills), [popnow-js](https://github.com/popnow-ai/popnow-js), [popnow-api](https://github.com/popnow-ai/popnow-api), [popnow-blender](https://github.com/popnow-ai/popnow-blender)
340
+
341
+ ## Contributing
342
+
343
+ Issues and pull requests are welcome; see [CONTRIBUTING.md](CONTRIBUTING.md). To report a vulnerability, see [SECURITY.md](SECURITY.md).
344
+
345
+ ## License
346
+
347
+ [MIT](LICENSE) © PopNow