bannerify 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.
bannerify-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: bannerify
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for Bannerify API - Generate images and PDFs at scale
|
|
5
|
+
Keywords: bannerify,image generation,pdf generation,api
|
|
6
|
+
Author: Duc An
|
|
7
|
+
Author-email: Duc An <an@bannerify.co>
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Requires-Dist: httpx>=0.27.0
|
|
19
|
+
Requires-Dist: pydantic>=2.0
|
|
20
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Project-URL: Documentation, https://bannerify.co/docs
|
|
23
|
+
Project-URL: Homepage, https://bannerify.co
|
|
24
|
+
Project-URL: Issues, https://github.com/bannerify/bannerify-python/issues
|
|
25
|
+
Project-URL: Repository, https://github.com/bannerify/bannerify-python
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Bannerify Python SDK
|
|
29
|
+
|
|
30
|
+
Official Python SDK for [Bannerify](https://bannerify.co) - Generate images and PDFs at scale via API.
|
|
31
|
+
|
|
32
|
+
[](https://badge.fury.io/py/bannerify)
|
|
33
|
+
[](https://pypi.org/project/bannerify/)
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install bannerify
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or with uv:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv add bannerify
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from bannerify import BannerifyClient
|
|
51
|
+
|
|
52
|
+
# Create client with your API key
|
|
53
|
+
client = BannerifyClient("your-api-key")
|
|
54
|
+
|
|
55
|
+
# Generate an image
|
|
56
|
+
result = client.create_image(
|
|
57
|
+
"tpl_xxxxxxxxx",
|
|
58
|
+
modifications=[
|
|
59
|
+
{"name": "title", "text": "Hello World"},
|
|
60
|
+
{"name": "subtitle", "text": "From Python SDK"}
|
|
61
|
+
]
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if "result" in result:
|
|
65
|
+
with open("output.png", "wb") as f:
|
|
66
|
+
f.write(result["result"])
|
|
67
|
+
print("Image created successfully!")
|
|
68
|
+
else:
|
|
69
|
+
print(f"Error: {result['error']['message']}")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Features
|
|
73
|
+
|
|
74
|
+
- 🚀 Simple, intuitive API
|
|
75
|
+
- 🔒 Type-safe with full type hints
|
|
76
|
+
- ⚡ Built on httpx for performance
|
|
77
|
+
- 🎯 Result/Error pattern for explicit error handling
|
|
78
|
+
- 📝 Comprehensive documentation
|
|
79
|
+
- ✅ Well-tested
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
### Creating Images
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
# Generate PNG
|
|
87
|
+
result = client.create_image(
|
|
88
|
+
"tpl_xxxxxxxxx",
|
|
89
|
+
modifications=[
|
|
90
|
+
{"name": "title", "text": "My Title"},
|
|
91
|
+
{"name": "image", "src": "https://example.com/image.jpg"}
|
|
92
|
+
]
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Generate SVG
|
|
96
|
+
result = client.create_image(
|
|
97
|
+
"tpl_xxxxxxxxx",
|
|
98
|
+
format="svg",
|
|
99
|
+
modifications=[{"name": "title", "text": "My Title"}]
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Generate thumbnail
|
|
103
|
+
result = client.create_image("tpl_xxxxxxxxx", thumbnail=True)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Creating PDFs
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
result = client.create_pdf(
|
|
110
|
+
"tpl_xxxxxxxxx",
|
|
111
|
+
modifications=[{"name": "title", "text": "Invoice #123"}]
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
if "result" in result:
|
|
115
|
+
with open("invoice.pdf", "wb") as f:
|
|
116
|
+
f.write(result["result"])
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Generating Signed URLs
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
signed_url = client.generate_image_signed_url(
|
|
123
|
+
"tpl_xxxxxxxxx",
|
|
124
|
+
modifications=[{"name": "title", "text": "Dynamic Title"}],
|
|
125
|
+
format="png"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# Use in HTML
|
|
129
|
+
print(f"<img src='{signed_url}' alt='Generated Image' />")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Error Handling
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
result = client.create_image("tpl_xxxxxxxxx")
|
|
136
|
+
|
|
137
|
+
if "error" in result:
|
|
138
|
+
error = result["error"]
|
|
139
|
+
print(f"Error Code: {error['code']}")
|
|
140
|
+
print(f"Message: {error['message']}")
|
|
141
|
+
print(f"Docs: {error['docs']}")
|
|
142
|
+
else:
|
|
143
|
+
# Process result
|
|
144
|
+
image_data = result["result"]
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Context Manager
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
with BannerifyClient("your-api-key") as client:
|
|
151
|
+
result = client.create_image("tpl_xxxxxxxxx")
|
|
152
|
+
# Client is automatically closed
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## API Reference
|
|
156
|
+
|
|
157
|
+
### BannerifyClient
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
BannerifyClient(
|
|
161
|
+
api_key: str,
|
|
162
|
+
base_url: str = "https://api.bannerify.co/v1",
|
|
163
|
+
timeout: float = 60.0
|
|
164
|
+
)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### create_image
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
client.create_image(
|
|
171
|
+
template_id: str,
|
|
172
|
+
modifications: Optional[List[Dict[str, Any]]] = None,
|
|
173
|
+
format: str = "png",
|
|
174
|
+
thumbnail: bool = False
|
|
175
|
+
) -> Dict[str, Any]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### create_pdf
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
client.create_pdf(
|
|
182
|
+
template_id: str,
|
|
183
|
+
modifications: Optional[List[Dict[str, Any]]] = None
|
|
184
|
+
) -> Dict[str, Any]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### create_stored_image
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
client.create_stored_image(
|
|
191
|
+
template_id: str,
|
|
192
|
+
modifications: Optional[List[Dict[str, Any]]] = None,
|
|
193
|
+
format: str = "png",
|
|
194
|
+
thumbnail: bool = False
|
|
195
|
+
) -> Dict[str, Any]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### generate_image_signed_url
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
client.generate_image_signed_url(
|
|
202
|
+
template_id: str,
|
|
203
|
+
modifications: Optional[List[Dict[str, Any]]] = None,
|
|
204
|
+
format: str = "png",
|
|
205
|
+
thumbnail: bool = False,
|
|
206
|
+
nocache: bool = False
|
|
207
|
+
) -> str
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Examples
|
|
211
|
+
|
|
212
|
+
### Generate Multiple Images
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
products = [
|
|
216
|
+
{"name": "Product A", "price": "$29.99"},
|
|
217
|
+
{"name": "Product B", "price": "$39.99"},
|
|
218
|
+
]
|
|
219
|
+
|
|
220
|
+
for i, product in enumerate(products):
|
|
221
|
+
result = client.create_image(
|
|
222
|
+
"tpl_product_banner",
|
|
223
|
+
modifications=[
|
|
224
|
+
{"name": "product_name", "text": product["name"]},
|
|
225
|
+
{"name": "price", "text": product["price"]}
|
|
226
|
+
]
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
if "result" in result:
|
|
230
|
+
with open(f"banner_{i}.png", "wb") as f:
|
|
231
|
+
f.write(result["result"])
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Email Campaigns
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
for recipient in recipients:
|
|
238
|
+
signed_url = client.generate_image_signed_url(
|
|
239
|
+
"tpl_email_header",
|
|
240
|
+
modifications=[{"name": "name", "text": f"Hi, {recipient['name']}!"}]
|
|
241
|
+
)
|
|
242
|
+
# Use signed_url in email HTML
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Development
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# Install dependencies
|
|
249
|
+
uv sync
|
|
250
|
+
|
|
251
|
+
# Run tests
|
|
252
|
+
uv run pytest
|
|
253
|
+
|
|
254
|
+
# Type checking
|
|
255
|
+
uv run mypy src/
|
|
256
|
+
|
|
257
|
+
# Format code
|
|
258
|
+
uv run ruff format src/
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Documentation
|
|
262
|
+
|
|
263
|
+
Full documentation available at [https://bannerify.co/docs/sdk/python/overview](https://bannerify.co/docs/sdk/python/overview)
|
|
264
|
+
|
|
265
|
+
## Support
|
|
266
|
+
|
|
267
|
+
- Documentation: https://bannerify.co/docs
|
|
268
|
+
- Issues: https://github.com/bannerify/bannerify-python/issues
|
|
269
|
+
- Email: support@bannerify.co
|
|
270
|
+
|
|
271
|
+
## License
|
|
272
|
+
|
|
273
|
+
MIT License - see LICENSE file for details
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# Bannerify Python SDK
|
|
2
|
+
|
|
3
|
+
Official Python SDK for [Bannerify](https://bannerify.co) - Generate images and PDFs at scale via API.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/py/bannerify)
|
|
6
|
+
[](https://pypi.org/project/bannerify/)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install bannerify
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Or with uv:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
uv add bannerify
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from bannerify import BannerifyClient
|
|
24
|
+
|
|
25
|
+
# Create client with your API key
|
|
26
|
+
client = BannerifyClient("your-api-key")
|
|
27
|
+
|
|
28
|
+
# Generate an image
|
|
29
|
+
result = client.create_image(
|
|
30
|
+
"tpl_xxxxxxxxx",
|
|
31
|
+
modifications=[
|
|
32
|
+
{"name": "title", "text": "Hello World"},
|
|
33
|
+
{"name": "subtitle", "text": "From Python SDK"}
|
|
34
|
+
]
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if "result" in result:
|
|
38
|
+
with open("output.png", "wb") as f:
|
|
39
|
+
f.write(result["result"])
|
|
40
|
+
print("Image created successfully!")
|
|
41
|
+
else:
|
|
42
|
+
print(f"Error: {result['error']['message']}")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- 🚀 Simple, intuitive API
|
|
48
|
+
- 🔒 Type-safe with full type hints
|
|
49
|
+
- ⚡ Built on httpx for performance
|
|
50
|
+
- 🎯 Result/Error pattern for explicit error handling
|
|
51
|
+
- 📝 Comprehensive documentation
|
|
52
|
+
- ✅ Well-tested
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
|
|
56
|
+
### Creating Images
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
# Generate PNG
|
|
60
|
+
result = client.create_image(
|
|
61
|
+
"tpl_xxxxxxxxx",
|
|
62
|
+
modifications=[
|
|
63
|
+
{"name": "title", "text": "My Title"},
|
|
64
|
+
{"name": "image", "src": "https://example.com/image.jpg"}
|
|
65
|
+
]
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Generate SVG
|
|
69
|
+
result = client.create_image(
|
|
70
|
+
"tpl_xxxxxxxxx",
|
|
71
|
+
format="svg",
|
|
72
|
+
modifications=[{"name": "title", "text": "My Title"}]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# Generate thumbnail
|
|
76
|
+
result = client.create_image("tpl_xxxxxxxxx", thumbnail=True)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Creating PDFs
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
result = client.create_pdf(
|
|
83
|
+
"tpl_xxxxxxxxx",
|
|
84
|
+
modifications=[{"name": "title", "text": "Invoice #123"}]
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if "result" in result:
|
|
88
|
+
with open("invoice.pdf", "wb") as f:
|
|
89
|
+
f.write(result["result"])
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Generating Signed URLs
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
signed_url = client.generate_image_signed_url(
|
|
96
|
+
"tpl_xxxxxxxxx",
|
|
97
|
+
modifications=[{"name": "title", "text": "Dynamic Title"}],
|
|
98
|
+
format="png"
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Use in HTML
|
|
102
|
+
print(f"<img src='{signed_url}' alt='Generated Image' />")
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Error Handling
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
result = client.create_image("tpl_xxxxxxxxx")
|
|
109
|
+
|
|
110
|
+
if "error" in result:
|
|
111
|
+
error = result["error"]
|
|
112
|
+
print(f"Error Code: {error['code']}")
|
|
113
|
+
print(f"Message: {error['message']}")
|
|
114
|
+
print(f"Docs: {error['docs']}")
|
|
115
|
+
else:
|
|
116
|
+
# Process result
|
|
117
|
+
image_data = result["result"]
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Context Manager
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
with BannerifyClient("your-api-key") as client:
|
|
124
|
+
result = client.create_image("tpl_xxxxxxxxx")
|
|
125
|
+
# Client is automatically closed
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## API Reference
|
|
129
|
+
|
|
130
|
+
### BannerifyClient
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
BannerifyClient(
|
|
134
|
+
api_key: str,
|
|
135
|
+
base_url: str = "https://api.bannerify.co/v1",
|
|
136
|
+
timeout: float = 60.0
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### create_image
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
client.create_image(
|
|
144
|
+
template_id: str,
|
|
145
|
+
modifications: Optional[List[Dict[str, Any]]] = None,
|
|
146
|
+
format: str = "png",
|
|
147
|
+
thumbnail: bool = False
|
|
148
|
+
) -> Dict[str, Any]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### create_pdf
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
client.create_pdf(
|
|
155
|
+
template_id: str,
|
|
156
|
+
modifications: Optional[List[Dict[str, Any]]] = None
|
|
157
|
+
) -> Dict[str, Any]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### create_stored_image
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
client.create_stored_image(
|
|
164
|
+
template_id: str,
|
|
165
|
+
modifications: Optional[List[Dict[str, Any]]] = None,
|
|
166
|
+
format: str = "png",
|
|
167
|
+
thumbnail: bool = False
|
|
168
|
+
) -> Dict[str, Any]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### generate_image_signed_url
|
|
172
|
+
|
|
173
|
+
```python
|
|
174
|
+
client.generate_image_signed_url(
|
|
175
|
+
template_id: str,
|
|
176
|
+
modifications: Optional[List[Dict[str, Any]]] = None,
|
|
177
|
+
format: str = "png",
|
|
178
|
+
thumbnail: bool = False,
|
|
179
|
+
nocache: bool = False
|
|
180
|
+
) -> str
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Examples
|
|
184
|
+
|
|
185
|
+
### Generate Multiple Images
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
products = [
|
|
189
|
+
{"name": "Product A", "price": "$29.99"},
|
|
190
|
+
{"name": "Product B", "price": "$39.99"},
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
for i, product in enumerate(products):
|
|
194
|
+
result = client.create_image(
|
|
195
|
+
"tpl_product_banner",
|
|
196
|
+
modifications=[
|
|
197
|
+
{"name": "product_name", "text": product["name"]},
|
|
198
|
+
{"name": "price", "text": product["price"]}
|
|
199
|
+
]
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if "result" in result:
|
|
203
|
+
with open(f"banner_{i}.png", "wb") as f:
|
|
204
|
+
f.write(result["result"])
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Email Campaigns
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
for recipient in recipients:
|
|
211
|
+
signed_url = client.generate_image_signed_url(
|
|
212
|
+
"tpl_email_header",
|
|
213
|
+
modifications=[{"name": "name", "text": f"Hi, {recipient['name']}!"}]
|
|
214
|
+
)
|
|
215
|
+
# Use signed_url in email HTML
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Development
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
# Install dependencies
|
|
222
|
+
uv sync
|
|
223
|
+
|
|
224
|
+
# Run tests
|
|
225
|
+
uv run pytest
|
|
226
|
+
|
|
227
|
+
# Type checking
|
|
228
|
+
uv run mypy src/
|
|
229
|
+
|
|
230
|
+
# Format code
|
|
231
|
+
uv run ruff format src/
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Documentation
|
|
235
|
+
|
|
236
|
+
Full documentation available at [https://bannerify.co/docs/sdk/python/overview](https://bannerify.co/docs/sdk/python/overview)
|
|
237
|
+
|
|
238
|
+
## Support
|
|
239
|
+
|
|
240
|
+
- Documentation: https://bannerify.co/docs
|
|
241
|
+
- Issues: https://github.com/bannerify/bannerify-python/issues
|
|
242
|
+
- Email: support@bannerify.co
|
|
243
|
+
|
|
244
|
+
## License
|
|
245
|
+
|
|
246
|
+
MIT License - see LICENSE file for details
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "bannerify"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Official Python SDK for Bannerify API - Generate images and PDFs at scale"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "Duc An", email = "an@bannerify.co" }]
|
|
7
|
+
requires-python = ">=3.8"
|
|
8
|
+
dependencies = ["httpx>=0.27.0", "pydantic>=2.0", "python-dotenv>=1.0.1"]
|
|
9
|
+
license = { text = "MIT" }
|
|
10
|
+
keywords = ["bannerify", "image generation", "pdf generation", "api"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Intended Audience :: Developers",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
"Programming Language :: Python :: 3.8",
|
|
17
|
+
"Programming Language :: Python :: 3.9",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.urls]
|
|
24
|
+
Homepage = "https://bannerify.co"
|
|
25
|
+
Documentation = "https://bannerify.co/docs"
|
|
26
|
+
Repository = "https://github.com/bannerify/bannerify-python"
|
|
27
|
+
Issues = "https://github.com/bannerify/bannerify-python/issues"
|
|
28
|
+
|
|
29
|
+
[build-system]
|
|
30
|
+
requires = ["uv_build>=0.8.23,<0.9.0"]
|
|
31
|
+
build-backend = "uv_build"
|
|
32
|
+
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = ["datamodel-code-generator>=0.27.3"]
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
"""Bannerify Client for Python"""
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
from typing import Any, Dict, List, Optional, Union
|
|
6
|
+
from urllib.parse import urlencode
|
|
7
|
+
|
|
8
|
+
import httpx
|
|
9
|
+
from pydantic import TypeAdapter
|
|
10
|
+
|
|
11
|
+
from .models import Modification
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BannerifyClient:
|
|
15
|
+
"""Bannerify API Client
|
|
16
|
+
|
|
17
|
+
A simple, developer-friendly client for the Bannerify API.
|
|
18
|
+
Generate images and PDFs from templates at scale.
|
|
19
|
+
|
|
20
|
+
Example:
|
|
21
|
+
>>> client = BannerifyClient("your-api-key")
|
|
22
|
+
>>> result = client.create_image("tpl_xxx", modifications=[
|
|
23
|
+
... {"name": "title", "text": "Hello World"}
|
|
24
|
+
... ])
|
|
25
|
+
>>> if "result" in result:
|
|
26
|
+
... with open("output.png", "wb") as f:
|
|
27
|
+
... f.write(result["result"])
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
api_key: str,
|
|
33
|
+
base_url: str = "https://api.bannerify.co/v1",
|
|
34
|
+
timeout: float = 60.0,
|
|
35
|
+
):
|
|
36
|
+
"""Initialize the Bannerify client
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
api_key: Your Bannerify API key
|
|
40
|
+
base_url: API base URL (default: https://api.bannerify.co/v1)
|
|
41
|
+
timeout: Request timeout in seconds (default: 60.0)
|
|
42
|
+
"""
|
|
43
|
+
self.api_key = api_key
|
|
44
|
+
self.base_url = base_url.rstrip("/")
|
|
45
|
+
self.timeout = timeout
|
|
46
|
+
self._client = httpx.Client(
|
|
47
|
+
timeout=timeout,
|
|
48
|
+
headers={
|
|
49
|
+
"Authorization": f"Bearer {api_key}",
|
|
50
|
+
"User-Agent": "bannerify-python/0.1.0",
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def __enter__(self):
|
|
55
|
+
return self
|
|
56
|
+
|
|
57
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
58
|
+
self.close()
|
|
59
|
+
|
|
60
|
+
def close(self):
|
|
61
|
+
"""Close the HTTP client"""
|
|
62
|
+
self._client.close()
|
|
63
|
+
|
|
64
|
+
def create_image(
|
|
65
|
+
self,
|
|
66
|
+
template_id: str,
|
|
67
|
+
modifications: Optional[List[Union[Modification, Dict[str, Any]]]] = None,
|
|
68
|
+
format: str = "png",
|
|
69
|
+
thumbnail: bool = False,
|
|
70
|
+
) -> Dict[str, Any]:
|
|
71
|
+
"""Generate an image from a template
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
template_id: Template ID (e.g., 'tpl_xxxxxxxxx')
|
|
75
|
+
modifications: List of modifications to apply
|
|
76
|
+
format: Output format - 'png' or 'svg' (default: 'png')
|
|
77
|
+
thumbnail: Generate thumbnail version (default: False)
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Dict with either 'result' (bytes) or 'error' (dict)
|
|
81
|
+
|
|
82
|
+
Example:
|
|
83
|
+
>>> result = client.create_image(
|
|
84
|
+
... "tpl_xxx",
|
|
85
|
+
... modifications=[{"name": "title", "text": "Hello"}],
|
|
86
|
+
... format="png"
|
|
87
|
+
... )
|
|
88
|
+
"""
|
|
89
|
+
try:
|
|
90
|
+
# Convert modifications to dicts if they're Pydantic models
|
|
91
|
+
mods_list = []
|
|
92
|
+
if modifications:
|
|
93
|
+
for mod in modifications:
|
|
94
|
+
if isinstance(mod, Modification):
|
|
95
|
+
mods_list.append(mod.model_dump(exclude_none=True))
|
|
96
|
+
else:
|
|
97
|
+
mods_list.append(mod)
|
|
98
|
+
|
|
99
|
+
payload = {
|
|
100
|
+
"apiKey": self.api_key,
|
|
101
|
+
"templateId": template_id,
|
|
102
|
+
"modifications": mods_list,
|
|
103
|
+
"format": format,
|
|
104
|
+
"thumbnail": thumbnail,
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
response = self._client.post(
|
|
108
|
+
f"{self.base_url}/templates/createImage",
|
|
109
|
+
json=payload,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if response.status_code == 200:
|
|
113
|
+
content_type = response.headers.get("content-type", "")
|
|
114
|
+
|
|
115
|
+
if "image/svg" in content_type:
|
|
116
|
+
return {"result": response.text}
|
|
117
|
+
else:
|
|
118
|
+
return {"result": response.content}
|
|
119
|
+
|
|
120
|
+
# Handle error responses
|
|
121
|
+
if response.headers.get("content-type", "").startswith("application/json"):
|
|
122
|
+
error_data = response.json()
|
|
123
|
+
if "error" in error_data:
|
|
124
|
+
return {"error": error_data["error"]}
|
|
125
|
+
|
|
126
|
+
return self._build_error(
|
|
127
|
+
"HTTP_ERROR",
|
|
128
|
+
f"HTTP {response.status_code}: {response.text[:100]}"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
except httpx.TimeoutException:
|
|
132
|
+
return self._build_error("TIMEOUT", "Request timed out")
|
|
133
|
+
except httpx.RequestError as e:
|
|
134
|
+
return self._build_error("REQUEST_ERROR", str(e))
|
|
135
|
+
except Exception as e:
|
|
136
|
+
return self._build_error("EXCEPTION", str(e))
|
|
137
|
+
|
|
138
|
+
def create_pdf(
|
|
139
|
+
self,
|
|
140
|
+
template_id: str,
|
|
141
|
+
modifications: Optional[List[Union[Modification, Dict[str, Any]]]] = None,
|
|
142
|
+
) -> Dict[str, Any]:
|
|
143
|
+
"""Generate a PDF from a template
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
template_id: Template ID
|
|
147
|
+
modifications: List of modifications to apply
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Dict with either 'result' (bytes) or 'error' (dict)
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
# Convert modifications to dicts if they're Pydantic models
|
|
154
|
+
mods_list = []
|
|
155
|
+
if modifications:
|
|
156
|
+
for mod in modifications:
|
|
157
|
+
if isinstance(mod, Modification):
|
|
158
|
+
mods_list.append(mod.model_dump(exclude_none=True))
|
|
159
|
+
else:
|
|
160
|
+
mods_list.append(mod)
|
|
161
|
+
|
|
162
|
+
payload = {
|
|
163
|
+
"apiKey": self.api_key,
|
|
164
|
+
"templateId": template_id,
|
|
165
|
+
"modifications": mods_list,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
response = self._client.post(
|
|
169
|
+
f"{self.base_url}/templates/createPdf",
|
|
170
|
+
json=payload,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
if response.status_code == 200:
|
|
174
|
+
return {"result": response.content}
|
|
175
|
+
|
|
176
|
+
# Handle error responses
|
|
177
|
+
if response.headers.get("content-type", "").startswith("application/json"):
|
|
178
|
+
error_data = response.json()
|
|
179
|
+
if "error" in error_data:
|
|
180
|
+
return {"error": error_data["error"]}
|
|
181
|
+
|
|
182
|
+
return self._build_error(
|
|
183
|
+
"HTTP_ERROR",
|
|
184
|
+
f"HTTP {response.status_code}: {response.text[:100]}"
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
except httpx.TimeoutException:
|
|
188
|
+
return self._build_error("TIMEOUT", "Request timed out")
|
|
189
|
+
except httpx.RequestError as e:
|
|
190
|
+
return self._build_error("REQUEST_ERROR", str(e))
|
|
191
|
+
except Exception as e:
|
|
192
|
+
return self._build_error("EXCEPTION", str(e))
|
|
193
|
+
|
|
194
|
+
def create_stored_image(
|
|
195
|
+
self,
|
|
196
|
+
template_id: str,
|
|
197
|
+
modifications: Optional[List[Union[Modification, Dict[str, Any]]]] = None,
|
|
198
|
+
format: str = "png",
|
|
199
|
+
thumbnail: bool = False,
|
|
200
|
+
) -> Dict[str, Any]:
|
|
201
|
+
"""Create an image and store it on Bannerify's CDN
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
template_id: Template ID
|
|
205
|
+
modifications: List of modifications to apply
|
|
206
|
+
format: Output format - 'png' or 'svg'
|
|
207
|
+
thumbnail: Generate thumbnail version
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
Dict with either 'result' (URL string) or 'error' (dict)
|
|
211
|
+
"""
|
|
212
|
+
try:
|
|
213
|
+
# Convert modifications to dicts if they're Pydantic models
|
|
214
|
+
mods_list = []
|
|
215
|
+
if modifications:
|
|
216
|
+
for mod in modifications:
|
|
217
|
+
if isinstance(mod, Modification):
|
|
218
|
+
mods_list.append(mod.model_dump(exclude_none=True))
|
|
219
|
+
else:
|
|
220
|
+
mods_list.append(mod)
|
|
221
|
+
|
|
222
|
+
payload = {
|
|
223
|
+
"apiKey": self.api_key,
|
|
224
|
+
"templateId": template_id,
|
|
225
|
+
"modifications": mods_list,
|
|
226
|
+
"format": format,
|
|
227
|
+
"thumbnail": thumbnail,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
response = self._client.post(
|
|
231
|
+
f"{self.base_url}/templates/createStoredImage",
|
|
232
|
+
json=payload,
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
if response.status_code == 200:
|
|
236
|
+
data = response.json()
|
|
237
|
+
return {"result": data.get("url")}
|
|
238
|
+
|
|
239
|
+
# Handle error responses
|
|
240
|
+
if response.headers.get("content-type", "").startswith("application/json"):
|
|
241
|
+
error_data = response.json()
|
|
242
|
+
if "error" in error_data:
|
|
243
|
+
return {"error": error_data["error"]}
|
|
244
|
+
|
|
245
|
+
return self._build_error(
|
|
246
|
+
"HTTP_ERROR",
|
|
247
|
+
f"HTTP {response.status_code}: {response.text[:100]}"
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
except httpx.TimeoutException:
|
|
251
|
+
return self._build_error("TIMEOUT", "Request timed out")
|
|
252
|
+
except httpx.RequestError as e:
|
|
253
|
+
return self._build_error("REQUEST_ERROR", str(e))
|
|
254
|
+
except Exception as e:
|
|
255
|
+
return self._build_error("EXCEPTION", str(e))
|
|
256
|
+
|
|
257
|
+
def generate_image_signed_url(
|
|
258
|
+
self,
|
|
259
|
+
template_id: str,
|
|
260
|
+
modifications: Optional[List[Union[Modification, Dict[str, Any]]]] = None,
|
|
261
|
+
format: str = "png",
|
|
262
|
+
thumbnail: bool = False,
|
|
263
|
+
nocache: bool = False,
|
|
264
|
+
) -> str:
|
|
265
|
+
"""Generate a signed URL for on-demand image generation
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
template_id: Template ID
|
|
269
|
+
modifications: List of modifications to apply
|
|
270
|
+
format: Output format - 'png' or 'svg'
|
|
271
|
+
thumbnail: Generate thumbnail version
|
|
272
|
+
nocache: Bypass cache
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
The signed URL string
|
|
276
|
+
|
|
277
|
+
Example:
|
|
278
|
+
>>> url = client.generate_image_signed_url(
|
|
279
|
+
... "tpl_xxx",
|
|
280
|
+
... modifications=[{"name": "title", "text": "Dynamic"}]
|
|
281
|
+
... )
|
|
282
|
+
>>> print(f"<img src='{url}' />")
|
|
283
|
+
"""
|
|
284
|
+
# Hash the API key
|
|
285
|
+
api_key_hashed = hashlib.sha256(self.api_key.encode()).hexdigest()
|
|
286
|
+
|
|
287
|
+
params = {
|
|
288
|
+
"apiKeyHashed": api_key_hashed,
|
|
289
|
+
"templateId": template_id,
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if format == "svg":
|
|
293
|
+
params["format"] = "svg"
|
|
294
|
+
|
|
295
|
+
if modifications:
|
|
296
|
+
# Convert modifications to dicts if they're Pydantic models
|
|
297
|
+
mods_list = []
|
|
298
|
+
for mod in modifications:
|
|
299
|
+
if isinstance(mod, Modification):
|
|
300
|
+
mods_list.append(mod.model_dump(exclude_none=True))
|
|
301
|
+
else:
|
|
302
|
+
mods_list.append(mod)
|
|
303
|
+
params["modifications"] = json.dumps(mods_list)
|
|
304
|
+
|
|
305
|
+
if nocache:
|
|
306
|
+
params["nocache"] = "true"
|
|
307
|
+
|
|
308
|
+
if thumbnail:
|
|
309
|
+
params["thumbnail"] = "true"
|
|
310
|
+
|
|
311
|
+
# Sort parameters
|
|
312
|
+
sorted_params = dict(sorted(params.items()))
|
|
313
|
+
|
|
314
|
+
# Generate signature
|
|
315
|
+
query_string = urlencode(sorted_params)
|
|
316
|
+
sign_input = query_string + api_key_hashed
|
|
317
|
+
sign = hashlib.sha256(sign_input.encode()).hexdigest()
|
|
318
|
+
sorted_params["sign"] = sign
|
|
319
|
+
|
|
320
|
+
return f"{self.base_url}/templates/signedurl?{urlencode(sorted_params)}"
|
|
321
|
+
|
|
322
|
+
def _build_error(self, code: str, message: str) -> Dict[str, Any]:
|
|
323
|
+
"""Build an error response
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
code: Error code
|
|
327
|
+
message: Error message
|
|
328
|
+
|
|
329
|
+
Returns:
|
|
330
|
+
Error dict
|
|
331
|
+
"""
|
|
332
|
+
return {
|
|
333
|
+
"error": {
|
|
334
|
+
"code": code,
|
|
335
|
+
"message": message,
|
|
336
|
+
"docs": "https://bannerify.co/docs",
|
|
337
|
+
}
|
|
338
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# generated by datamodel-codegen:
|
|
2
|
+
# filename: openapi.json
|
|
3
|
+
# timestamp: 2025-11-14T19:40:03+00:00
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import Any, Dict, List, Optional
|
|
9
|
+
|
|
10
|
+
from pydantic import BaseModel, Field
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Code(Enum):
|
|
14
|
+
BAD_REQUEST = 'BAD_REQUEST'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Error(BaseModel):
|
|
18
|
+
code: Code = Field(
|
|
19
|
+
..., description='A machine readable error code.', example='BAD_REQUEST'
|
|
20
|
+
)
|
|
21
|
+
docs: str = Field(
|
|
22
|
+
...,
|
|
23
|
+
description='A link to our documentation with more details about this error code',
|
|
24
|
+
example='https://documentation.bannerify.co/api-reference/errors/code/BAD_REQUEST',
|
|
25
|
+
)
|
|
26
|
+
message: str = Field(
|
|
27
|
+
..., description='A human readable explanation of what went wrong'
|
|
28
|
+
)
|
|
29
|
+
requestId: str = Field(
|
|
30
|
+
...,
|
|
31
|
+
description='Please always include the requestId in your error report',
|
|
32
|
+
example='req:1234',
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ErrBadRequest(BaseModel):
|
|
37
|
+
error: Error
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Code1(Enum):
|
|
41
|
+
FETCH_IMAGE_ERROR = 'FETCH_IMAGE_ERROR'
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class Error1(BaseModel):
|
|
45
|
+
code: Code1 = Field(
|
|
46
|
+
..., description='A machine readable error code.', example='FETCH_IMAGE_ERROR'
|
|
47
|
+
)
|
|
48
|
+
docs: str = Field(
|
|
49
|
+
...,
|
|
50
|
+
description='A link to our documentation with more details about this error code',
|
|
51
|
+
example='https://documentation.bannerify.co/api-reference/errors/code/FETCH_IMAGE_ERROR',
|
|
52
|
+
)
|
|
53
|
+
message: str = Field(
|
|
54
|
+
..., description='A human readable explanation of what went wrong'
|
|
55
|
+
)
|
|
56
|
+
requestId: str = Field(
|
|
57
|
+
...,
|
|
58
|
+
description='Please always include the requestId in your error report',
|
|
59
|
+
example='req:1234',
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ErrFetchImageError(BaseModel):
|
|
64
|
+
error: Error1
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class Code2(Enum):
|
|
68
|
+
UNAUTHORIZED = 'UNAUTHORIZED'
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class Error2(BaseModel):
|
|
72
|
+
code: Code2 = Field(
|
|
73
|
+
..., description='A machine readable error code.', example='UNAUTHORIZED'
|
|
74
|
+
)
|
|
75
|
+
docs: str = Field(
|
|
76
|
+
...,
|
|
77
|
+
description='A link to our documentation with more details about this error code',
|
|
78
|
+
example='https://documentation.bannerify.co/api-reference/errors/code/UNAUTHORIZED',
|
|
79
|
+
)
|
|
80
|
+
message: str = Field(
|
|
81
|
+
..., description='A human readable explanation of what went wrong'
|
|
82
|
+
)
|
|
83
|
+
requestId: str = Field(
|
|
84
|
+
...,
|
|
85
|
+
description='Please always include the requestId in your error report',
|
|
86
|
+
example='req:1234',
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class ErrUnauthorized(BaseModel):
|
|
91
|
+
error: Error2
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class Code3(Enum):
|
|
95
|
+
FORBIDDEN = 'FORBIDDEN'
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class Error3(BaseModel):
|
|
99
|
+
code: Code3 = Field(
|
|
100
|
+
..., description='A machine readable error code.', example='FORBIDDEN'
|
|
101
|
+
)
|
|
102
|
+
docs: str = Field(
|
|
103
|
+
...,
|
|
104
|
+
description='A link to our documentation with more details about this error code',
|
|
105
|
+
example='https://documentation.bannerify.co/api-reference/errors/code/FORBIDDEN',
|
|
106
|
+
)
|
|
107
|
+
message: str = Field(
|
|
108
|
+
..., description='A human readable explanation of what went wrong'
|
|
109
|
+
)
|
|
110
|
+
requestId: str = Field(
|
|
111
|
+
...,
|
|
112
|
+
description='Please always include the requestId in your error report',
|
|
113
|
+
example='req:1234',
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class ErrForbidden(BaseModel):
|
|
118
|
+
error: Error3
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class Code4(Enum):
|
|
122
|
+
NOT_FOUND = 'NOT_FOUND'
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
class Error4(BaseModel):
|
|
126
|
+
code: Code4 = Field(
|
|
127
|
+
..., description='A machine readable error code.', example='NOT_FOUND'
|
|
128
|
+
)
|
|
129
|
+
docs: str = Field(
|
|
130
|
+
...,
|
|
131
|
+
description='A link to our documentation with more details about this error code',
|
|
132
|
+
example='https://documentation.bannerify.co/api-reference/errors/code/NOT_FOUND',
|
|
133
|
+
)
|
|
134
|
+
message: str = Field(
|
|
135
|
+
..., description='A human readable explanation of what went wrong'
|
|
136
|
+
)
|
|
137
|
+
requestId: str = Field(
|
|
138
|
+
...,
|
|
139
|
+
description='Please always include the requestId in your error report',
|
|
140
|
+
example='req:1234',
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class ErrNotFound(BaseModel):
|
|
145
|
+
error: Error4
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class Code5(Enum):
|
|
149
|
+
CONFLICT = 'CONFLICT'
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class Error5(BaseModel):
|
|
153
|
+
code: Code5 = Field(
|
|
154
|
+
..., description='A machine readable error code.', example='CONFLICT'
|
|
155
|
+
)
|
|
156
|
+
docs: str = Field(
|
|
157
|
+
...,
|
|
158
|
+
description='A link to our documentation with more details about this error code',
|
|
159
|
+
example='https://documentation.bannerify.co/api-reference/errors/code/CONFLICT',
|
|
160
|
+
)
|
|
161
|
+
message: str = Field(
|
|
162
|
+
..., description='A human readable explanation of what went wrong'
|
|
163
|
+
)
|
|
164
|
+
requestId: str = Field(
|
|
165
|
+
...,
|
|
166
|
+
description='Please always include the requestId in your error report',
|
|
167
|
+
example='req:1234',
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class ErrConflict(BaseModel):
|
|
172
|
+
error: Error5
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class Code6(Enum):
|
|
176
|
+
TOO_MANY_REQUESTS = 'TOO_MANY_REQUESTS'
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class Error6(BaseModel):
|
|
180
|
+
code: Code6 = Field(
|
|
181
|
+
..., description='A machine readable error code.', example='TOO_MANY_REQUESTS'
|
|
182
|
+
)
|
|
183
|
+
docs: str = Field(
|
|
184
|
+
...,
|
|
185
|
+
description='A link to our documentation with more details about this error code',
|
|
186
|
+
example='https://documentation.bannerify.co/api-reference/errors/code/TOO_MANY_REQUESTS',
|
|
187
|
+
)
|
|
188
|
+
message: str = Field(
|
|
189
|
+
..., description='A human readable explanation of what went wrong'
|
|
190
|
+
)
|
|
191
|
+
requestId: str = Field(
|
|
192
|
+
...,
|
|
193
|
+
description='Please always include the requestId in your error report',
|
|
194
|
+
example='req:1234',
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class ErrTooManyRequests(BaseModel):
|
|
199
|
+
error: Error6
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class Code7(Enum):
|
|
203
|
+
INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR'
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class Error7(BaseModel):
|
|
207
|
+
code: Code7 = Field(
|
|
208
|
+
...,
|
|
209
|
+
description='A machine readable error code.',
|
|
210
|
+
example='INTERNAL_SERVER_ERROR',
|
|
211
|
+
)
|
|
212
|
+
docs: str = Field(
|
|
213
|
+
...,
|
|
214
|
+
description='A link to our documentation with more details about this error code',
|
|
215
|
+
example='https://documentation.bannerify.co/api-reference/errors/code/INTERNAL_SERVER_ERROR',
|
|
216
|
+
)
|
|
217
|
+
message: str = Field(
|
|
218
|
+
..., description='A human readable explanation of what went wrong'
|
|
219
|
+
)
|
|
220
|
+
requestId: str = Field(
|
|
221
|
+
...,
|
|
222
|
+
description='Please always include the requestId in your error report',
|
|
223
|
+
example='req:1234',
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class ErrInternalServerError(BaseModel):
|
|
228
|
+
error: Error7
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class WidthMode(Enum):
|
|
232
|
+
standard = 'standard'
|
|
233
|
+
adaptive = 'adaptive'
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
class HeightMode(Enum):
|
|
237
|
+
standard = 'standard'
|
|
238
|
+
adaptive = 'adaptive'
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class Theme(Enum):
|
|
242
|
+
NONE = 'NONE'
|
|
243
|
+
DEFAULT = 'DEFAULT'
|
|
244
|
+
BRIGHT = 'BRIGHT'
|
|
245
|
+
SIMPLIFY = 'SIMPLIFY'
|
|
246
|
+
ARCO = 'ARCO'
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class Modification(BaseModel):
|
|
250
|
+
name: str = Field(
|
|
251
|
+
..., description='The layer name of the modification', example='Text 1'
|
|
252
|
+
)
|
|
253
|
+
color: Optional[str] = Field(
|
|
254
|
+
None, description='The color for the modification', example='#FF0000'
|
|
255
|
+
)
|
|
256
|
+
src: Optional[str] = Field(
|
|
257
|
+
None,
|
|
258
|
+
description='The source image for the modification',
|
|
259
|
+
example='https://example.com/image.jpg',
|
|
260
|
+
)
|
|
261
|
+
text: Optional[str] = Field(
|
|
262
|
+
None,
|
|
263
|
+
description='You can modify the text layer with this field',
|
|
264
|
+
example='Hello World',
|
|
265
|
+
)
|
|
266
|
+
barcode: Optional[str] = Field(
|
|
267
|
+
None,
|
|
268
|
+
description='Modify the barcode layer content with this field',
|
|
269
|
+
example='1234567890',
|
|
270
|
+
)
|
|
271
|
+
qrcode: Optional[str] = Field(
|
|
272
|
+
None,
|
|
273
|
+
description='Modify the qrcode layer content with this field',
|
|
274
|
+
example='Some text',
|
|
275
|
+
)
|
|
276
|
+
chart: Optional[Dict[str, Any]] = Field(
|
|
277
|
+
None, description="Update chart layer's data, follow chart.js data structure"
|
|
278
|
+
)
|
|
279
|
+
visible: Optional[bool] = Field(
|
|
280
|
+
None, description='Set the visibility of the field', example=True
|
|
281
|
+
)
|
|
282
|
+
star: Optional[float] = Field(None, description='Star value', example=5)
|
|
283
|
+
widthMode: Optional[WidthMode] = Field(
|
|
284
|
+
None, description='Table width mode', example='adaptive'
|
|
285
|
+
)
|
|
286
|
+
heightMode: Optional[HeightMode] = Field(
|
|
287
|
+
None, description='Table height mode', example='adaptive'
|
|
288
|
+
)
|
|
289
|
+
theme: Optional[Theme] = Field(None, description='Table theme', example='NONE')
|
|
290
|
+
rows: Optional[List[Any]] = Field(None, description='Table rows')
|
|
291
|
+
columns: Optional[List[str]] = Field(None, description='Table columns')
|
|
File without changes
|