@spicyapi/sdk 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +21 -0
- package/SECURITY.md +4 -0
- package/contracts/openapi.yaml +752 -0
- package/dist/src/docs/index.d.ts +10 -0
- package/dist/src/docs/index.d.ts.map +1 -0
- package/dist/src/docs/index.js +181 -0
- package/dist/src/docs/index.js.map +1 -0
- package/dist/src/generated/openapi.d.ts +888 -0
- package/dist/src/generated/openapi.d.ts.map +1 -0
- package/dist/src/generated/openapi.js +6 -0
- package/dist/src/generated/openapi.js.map +1 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/openapi.d.ts +2 -0
- package/dist/src/openapi.d.ts.map +1 -0
- package/dist/src/openapi.js +18 -0
- package/dist/src/openapi.js.map +1 -0
- package/dist/src/sdk/client.d.ts +41 -0
- package/dist/src/sdk/client.d.ts.map +1 -0
- package/dist/src/sdk/client.js +407 -0
- package/dist/src/sdk/client.js.map +1 -0
- package/dist/src/sdk/errors.d.ts +36 -0
- package/dist/src/sdk/errors.d.ts.map +1 -0
- package/dist/src/sdk/errors.js +53 -0
- package/dist/src/sdk/errors.js.map +1 -0
- package/dist/src/sdk/index.d.ts +4 -0
- package/dist/src/sdk/index.d.ts.map +1 -0
- package/dist/src/sdk/index.js +3 -0
- package/dist/src/sdk/index.js.map +1 -0
- package/dist/src/sdk/types.d.ts +73 -0
- package/dist/src/sdk/types.d.ts.map +1 -0
- package/dist/src/sdk/types.js +2 -0
- package/dist/src/sdk/types.js.map +1 -0
- package/dist/src/webhooks/index.d.ts +28 -0
- package/dist/src/webhooks/index.d.ts.map +1 -0
- package/dist/src/webhooks/index.js +83 -0
- package/dist/src/webhooks/index.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1,752 @@
|
|
|
1
|
+
openapi: 3.1.0
|
|
2
|
+
info:
|
|
3
|
+
title: SpicyAPI Public API
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
description: |
|
|
6
|
+
Contract for the implemented `/api/v1` integration surface.
|
|
7
|
+
|
|
8
|
+
Every operation requires a Bearer API key. Every JSON response uses the
|
|
9
|
+
`{code,msg,data,request_id}` envelope. A successful HTTP response has
|
|
10
|
+
`code: 200`; asynchronous task success or failure is expressed by
|
|
11
|
+
`data.state`, not by the envelope code.
|
|
12
|
+
servers:
|
|
13
|
+
- url: https://api.spicyapi.ai
|
|
14
|
+
description: Production
|
|
15
|
+
tags:
|
|
16
|
+
- name: Tasks
|
|
17
|
+
- name: Models
|
|
18
|
+
- name: Account
|
|
19
|
+
- name: Media
|
|
20
|
+
security:
|
|
21
|
+
- bearerAuth: []
|
|
22
|
+
paths:
|
|
23
|
+
/api/v1/jobs/createTask:
|
|
24
|
+
post:
|
|
25
|
+
tags: [Tasks]
|
|
26
|
+
operationId: createTask
|
|
27
|
+
summary: Create an asynchronous generation task
|
|
28
|
+
description: |
|
|
29
|
+
Validates the model input, reserves the estimated charge, chooses an
|
|
30
|
+
available deployment, and creates a task in `queued` state. HTTP 202
|
|
31
|
+
means the task was accepted; it does not mean generation has completed.
|
|
32
|
+
|
|
33
|
+
An `Idempotency-Key` is optional but strongly recommended. For the same
|
|
34
|
+
account **and the same API key**, repeating a key with the same normalized
|
|
35
|
+
model, input, callback URL, and mature flag within 24 hours returns the
|
|
36
|
+
original task and does not reserve funds twice. A sibling API key cannot
|
|
37
|
+
replay the mapping: it receives `409 Conflict` without the original task
|
|
38
|
+
ID. Reusing the key with different request semantics also returns
|
|
39
|
+
`409 Conflict`. Callbacks are optional and are validated against
|
|
40
|
+
private/loopback destinations before acceptance.
|
|
41
|
+
parameters:
|
|
42
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
43
|
+
requestBody:
|
|
44
|
+
required: true
|
|
45
|
+
content:
|
|
46
|
+
application/json:
|
|
47
|
+
schema:
|
|
48
|
+
$ref: '#/components/schemas/CreateTaskRequest'
|
|
49
|
+
responses:
|
|
50
|
+
'202':
|
|
51
|
+
description: A newly accepted task is returned in `queued` state. A same-key idempotent replay returns the original task in its current state and does not create another hold. The hold is not a charge.
|
|
52
|
+
headers:
|
|
53
|
+
Location:
|
|
54
|
+
description: Relative URL of the task status resource.
|
|
55
|
+
schema: { type: string }
|
|
56
|
+
Retry-After: { $ref: '#/components/headers/RetryAfter' }
|
|
57
|
+
Cache-Control:
|
|
58
|
+
description: Task submissions contain caller-specific state and must not be cached.
|
|
59
|
+
schema: { type: string, const: no-store }
|
|
60
|
+
X-RateLimit-Limit: { $ref: '#/components/headers/RateLimitLimit' }
|
|
61
|
+
X-RateLimit-Remaining: { $ref: '#/components/headers/RateLimitRemaining' }
|
|
62
|
+
content:
|
|
63
|
+
application/json:
|
|
64
|
+
schema:
|
|
65
|
+
$ref: '#/components/schemas/CreateTaskEnvelope'
|
|
66
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
67
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
68
|
+
'402': { $ref: '#/components/responses/PaymentRequired' }
|
|
69
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
70
|
+
'409': { $ref: '#/components/responses/Conflict' }
|
|
71
|
+
'413': { $ref: '#/components/responses/PayloadTooLarge' }
|
|
72
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
73
|
+
'500': { $ref: '#/components/responses/ServerError' }
|
|
74
|
+
'503': { $ref: '#/components/responses/Unavailable' }
|
|
75
|
+
callbacks:
|
|
76
|
+
onTaskTerminal:
|
|
77
|
+
'{$request.body#/callBackUrl}':
|
|
78
|
+
post:
|
|
79
|
+
summary: Deliver a terminal task record
|
|
80
|
+
description: |
|
|
81
|
+
Sent only when `callBackUrl` was supplied. New integrations use
|
|
82
|
+
payload version 2, whose body is the same envelope and task
|
|
83
|
+
record returned by `recordInfo`. Payload version 1 remains a
|
|
84
|
+
compatibility output and is selected by the version header.
|
|
85
|
+
|
|
86
|
+
Verify `X-Webhook-Signature` over
|
|
87
|
+
`taskId.timestamp.sha256(raw_body)` with HMAC-SHA256 and the
|
|
88
|
+
account webhook key. Select `taskId` from top-level `task_id`
|
|
89
|
+
for payload v1 and from `data.taskId` for payload v2, then
|
|
90
|
+
compare the Base64-encoded result in constant time.
|
|
91
|
+
Reject stale timestamps. A delivery may be retried and receivers
|
|
92
|
+
must be idempotent; in v2, `request_id` is the stable delivery ID.
|
|
93
|
+
parameters:
|
|
94
|
+
- name: X-Webhook-Timestamp
|
|
95
|
+
in: header
|
|
96
|
+
required: true
|
|
97
|
+
schema: { type: string, pattern: '^[0-9]+$' }
|
|
98
|
+
description: Unix timestamp used by the signature.
|
|
99
|
+
- name: X-Webhook-Signature
|
|
100
|
+
in: header
|
|
101
|
+
required: true
|
|
102
|
+
schema: { type: string }
|
|
103
|
+
description: Base64-encoded HMAC-SHA256 signature.
|
|
104
|
+
- name: X-Webhook-Payload-Version
|
|
105
|
+
in: header
|
|
106
|
+
required: true
|
|
107
|
+
schema: { type: integer, enum: [1, 2] }
|
|
108
|
+
requestBody:
|
|
109
|
+
required: true
|
|
110
|
+
content:
|
|
111
|
+
application/json:
|
|
112
|
+
schema:
|
|
113
|
+
oneOf:
|
|
114
|
+
- $ref: '#/components/schemas/TaskRecordEnvelope'
|
|
115
|
+
- $ref: '#/components/schemas/LegacyWebhookPayload'
|
|
116
|
+
responses:
|
|
117
|
+
'200':
|
|
118
|
+
description: Any 2xx response acknowledges delivery.
|
|
119
|
+
/api/v1/jobs/recordInfo:
|
|
120
|
+
get:
|
|
121
|
+
tags: [Tasks]
|
|
122
|
+
operationId: recordInfo
|
|
123
|
+
summary: Get a task created by the authenticated API key
|
|
124
|
+
parameters:
|
|
125
|
+
- name: taskId
|
|
126
|
+
in: query
|
|
127
|
+
required: true
|
|
128
|
+
schema: { type: string, minLength: 1 }
|
|
129
|
+
responses:
|
|
130
|
+
'200':
|
|
131
|
+
description: Current task record. Terminal and non-terminal states share this shape.
|
|
132
|
+
headers:
|
|
133
|
+
Cache-Control:
|
|
134
|
+
description: Task state is caller-specific and changes asynchronously.
|
|
135
|
+
schema: { type: string, const: no-store }
|
|
136
|
+
content:
|
|
137
|
+
application/json:
|
|
138
|
+
schema:
|
|
139
|
+
$ref: '#/components/schemas/TaskRecordEnvelope'
|
|
140
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
141
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
142
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
143
|
+
'404':
|
|
144
|
+
description: Task does not exist or belongs to another account or API key; these cases are indistinguishable.
|
|
145
|
+
headers:
|
|
146
|
+
Cache-Control:
|
|
147
|
+
schema: { type: string, const: no-store }
|
|
148
|
+
content:
|
|
149
|
+
application/json:
|
|
150
|
+
schema: { $ref: '#/components/schemas/ErrorEnvelope' }
|
|
151
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
152
|
+
'500': { $ref: '#/components/responses/ServerError' }
|
|
153
|
+
/api/v1/jobs/retry:
|
|
154
|
+
post:
|
|
155
|
+
tags: [Tasks]
|
|
156
|
+
operationId: retryTask
|
|
157
|
+
summary: Create a new task from a failed or expired task
|
|
158
|
+
description: |
|
|
159
|
+
The source terminal task is never modified. Current model schema,
|
|
160
|
+
pricing, permissions, balance, and routing are evaluated again. An
|
|
161
|
+
optional Idempotency-Key is scoped to the source task and retry action.
|
|
162
|
+
The source task must have been created by the same API key; unknown,
|
|
163
|
+
cross-account, and same-account cross-key task IDs all return 404.
|
|
164
|
+
parameters:
|
|
165
|
+
- $ref: '#/components/parameters/IdempotencyKey'
|
|
166
|
+
requestBody:
|
|
167
|
+
required: true
|
|
168
|
+
content:
|
|
169
|
+
application/json:
|
|
170
|
+
schema: { $ref: '#/components/schemas/TaskActionRequest' }
|
|
171
|
+
responses:
|
|
172
|
+
'200':
|
|
173
|
+
description: A newly created retry task is returned in `queued` state. An idempotent replay returns that retry task in its current state.
|
|
174
|
+
content:
|
|
175
|
+
application/json:
|
|
176
|
+
schema: { $ref: '#/components/schemas/RetryTaskEnvelope' }
|
|
177
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
178
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
179
|
+
'402': { $ref: '#/components/responses/PaymentRequired' }
|
|
180
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
181
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
182
|
+
'409': { $ref: '#/components/responses/Conflict' }
|
|
183
|
+
'413': { $ref: '#/components/responses/PayloadTooLarge' }
|
|
184
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
185
|
+
'500': { $ref: '#/components/responses/ServerError' }
|
|
186
|
+
'503': { $ref: '#/components/responses/Unavailable' }
|
|
187
|
+
/api/v1/models:
|
|
188
|
+
get:
|
|
189
|
+
tags: [Models]
|
|
190
|
+
operationId: listModels
|
|
191
|
+
summary: List callable models and account-specific prices
|
|
192
|
+
description: |
|
|
193
|
+
Returns all enabled models without pagination. The response is private
|
|
194
|
+
because prices include the authenticated account's group multiplier.
|
|
195
|
+
The server sends `Cache-Control: private, max-age=60`.
|
|
196
|
+
parameters:
|
|
197
|
+
- name: modality
|
|
198
|
+
in: query
|
|
199
|
+
schema: { type: string, enum: [image, video, audio, text] }
|
|
200
|
+
- name: provider
|
|
201
|
+
in: query
|
|
202
|
+
schema: { type: string }
|
|
203
|
+
- name: task
|
|
204
|
+
in: query
|
|
205
|
+
schema: { type: string }
|
|
206
|
+
description: Exact supported task, for example `text-to-image`.
|
|
207
|
+
- name: search
|
|
208
|
+
in: query
|
|
209
|
+
schema: { type: string, maxLength: 128 }
|
|
210
|
+
- name: includeSchema
|
|
211
|
+
in: query
|
|
212
|
+
schema:
|
|
213
|
+
oneOf:
|
|
214
|
+
- { type: boolean }
|
|
215
|
+
- { type: integer, enum: [0, 1] }
|
|
216
|
+
description: Include each model's input JSON Schema when `true` or `1`.
|
|
217
|
+
- name: includeExamples
|
|
218
|
+
in: query
|
|
219
|
+
schema:
|
|
220
|
+
oneOf:
|
|
221
|
+
- { type: boolean }
|
|
222
|
+
- { type: integer, enum: [0, 1] }
|
|
223
|
+
description: Include validated example inputs when `true` or `1`.
|
|
224
|
+
responses:
|
|
225
|
+
'200':
|
|
226
|
+
description: Model list.
|
|
227
|
+
headers:
|
|
228
|
+
Cache-Control:
|
|
229
|
+
schema: { type: string, const: 'private, max-age=60' }
|
|
230
|
+
content:
|
|
231
|
+
application/json:
|
|
232
|
+
schema:
|
|
233
|
+
$ref: '#/components/schemas/ModelListEnvelope'
|
|
234
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
235
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
236
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
237
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
238
|
+
'500': { $ref: '#/components/responses/ServerError' }
|
|
239
|
+
/api/v1/models/{model}:
|
|
240
|
+
get:
|
|
241
|
+
tags: [Models]
|
|
242
|
+
operationId: getModel
|
|
243
|
+
summary: Get one model, including its input JSON Schema
|
|
244
|
+
description: |
|
|
245
|
+
`model` is the exact value used by `createTask.model` and may contain
|
|
246
|
+
slashes. URL-encode embedded slashes when using clients that treat path
|
|
247
|
+
parameters as one segment (for example `bytedance%2Fseedance-2-fast`).
|
|
248
|
+
parameters:
|
|
249
|
+
- name: model
|
|
250
|
+
in: path
|
|
251
|
+
required: true
|
|
252
|
+
allowReserved: true
|
|
253
|
+
schema: { type: string, minLength: 1 }
|
|
254
|
+
responses:
|
|
255
|
+
'200':
|
|
256
|
+
description: Complete model record.
|
|
257
|
+
headers:
|
|
258
|
+
Cache-Control:
|
|
259
|
+
schema: { type: string, const: 'private, max-age=60' }
|
|
260
|
+
content:
|
|
261
|
+
application/json:
|
|
262
|
+
schema:
|
|
263
|
+
$ref: '#/components/schemas/ModelEnvelope'
|
|
264
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
265
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
266
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
267
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
268
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
269
|
+
'500': { $ref: '#/components/responses/ServerError' }
|
|
270
|
+
/api/v1/chat/credit:
|
|
271
|
+
get:
|
|
272
|
+
tags: [Account]
|
|
273
|
+
operationId: getCreditBalance
|
|
274
|
+
summary: Get the account balance
|
|
275
|
+
responses:
|
|
276
|
+
'200':
|
|
277
|
+
description: Available, held, and total balance in USD decimal strings.
|
|
278
|
+
content:
|
|
279
|
+
application/json:
|
|
280
|
+
schema:
|
|
281
|
+
$ref: '#/components/schemas/BalanceEnvelope'
|
|
282
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
283
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
284
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
285
|
+
'500': { $ref: '#/components/responses/ServerError' }
|
|
286
|
+
/api/v1/common/upload-url:
|
|
287
|
+
post:
|
|
288
|
+
tags: [Media]
|
|
289
|
+
operationId: createUploadUrl
|
|
290
|
+
summary: Create a presigned image upload ticket
|
|
291
|
+
description: |
|
|
292
|
+
The server generates the object key. Upload the exact declared number of
|
|
293
|
+
bytes with PUT and copy every returned header. Supported media types are
|
|
294
|
+
JPEG, PNG, WebP, and GIF; the default maximum is 10 MiB. After PUT,
|
|
295
|
+
call the file commit endpoint and use its spicy:// URI in task input.
|
|
296
|
+
requestBody:
|
|
297
|
+
required: true
|
|
298
|
+
content:
|
|
299
|
+
application/json:
|
|
300
|
+
schema:
|
|
301
|
+
$ref: '#/components/schemas/UploadURLRequest'
|
|
302
|
+
responses:
|
|
303
|
+
'200':
|
|
304
|
+
description: Presigned upload ticket.
|
|
305
|
+
content:
|
|
306
|
+
application/json:
|
|
307
|
+
schema:
|
|
308
|
+
$ref: '#/components/schemas/UploadURLEnvelope'
|
|
309
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
310
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
311
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
312
|
+
'413': { $ref: '#/components/responses/PayloadTooLarge' }
|
|
313
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
314
|
+
'500': { $ref: '#/components/responses/ServerError' }
|
|
315
|
+
/api/v1/files/{fileId}/commit:
|
|
316
|
+
post:
|
|
317
|
+
tags: [Media]
|
|
318
|
+
operationId: commitUploadedFile
|
|
319
|
+
summary: Commit a completed direct upload
|
|
320
|
+
description: |
|
|
321
|
+
Compares the stored byte count and media type with the ticket, checks
|
|
322
|
+
the image signature, computes SHA-256, and copies the temporary object
|
|
323
|
+
to an immutable private key. Only the returned spicy:// URI can be used
|
|
324
|
+
in task input. Repeating a successful commit is idempotent.
|
|
325
|
+
parameters:
|
|
326
|
+
- name: fileId
|
|
327
|
+
in: path
|
|
328
|
+
required: true
|
|
329
|
+
schema: { type: string, pattern: '^fil_' }
|
|
330
|
+
responses:
|
|
331
|
+
'200':
|
|
332
|
+
description: Ready tenant-scoped file reference.
|
|
333
|
+
content:
|
|
334
|
+
application/json:
|
|
335
|
+
schema: { $ref: '#/components/schemas/FileCommitEnvelope' }
|
|
336
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
337
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
338
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
339
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
340
|
+
'409': { $ref: '#/components/responses/Conflict' }
|
|
341
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
342
|
+
'500': { $ref: '#/components/responses/ServerError' }
|
|
343
|
+
/api/v1/common/download-url:
|
|
344
|
+
post:
|
|
345
|
+
tags: [Media]
|
|
346
|
+
operationId: createDownloadUrl
|
|
347
|
+
summary: Create a short-lived task output download URL
|
|
348
|
+
description: |
|
|
349
|
+
The server verifies both task ownership and that the requested key is an
|
|
350
|
+
output of that task. Leave `key` empty to select the first output.
|
|
351
|
+
requestBody:
|
|
352
|
+
required: true
|
|
353
|
+
content:
|
|
354
|
+
application/json:
|
|
355
|
+
schema:
|
|
356
|
+
$ref: '#/components/schemas/DownloadURLRequest'
|
|
357
|
+
responses:
|
|
358
|
+
'200':
|
|
359
|
+
description: Short-lived download ticket.
|
|
360
|
+
content:
|
|
361
|
+
application/json:
|
|
362
|
+
schema:
|
|
363
|
+
$ref: '#/components/schemas/DownloadURLEnvelope'
|
|
364
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
365
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
366
|
+
'403': { $ref: '#/components/responses/Forbidden' }
|
|
367
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
368
|
+
'409': { $ref: '#/components/responses/Conflict' }
|
|
369
|
+
'413': { $ref: '#/components/responses/PayloadTooLarge' }
|
|
370
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
371
|
+
'500': { $ref: '#/components/responses/ServerError' }
|
|
372
|
+
components:
|
|
373
|
+
securitySchemes:
|
|
374
|
+
bearerAuth:
|
|
375
|
+
type: http
|
|
376
|
+
scheme: bearer
|
|
377
|
+
bearerFormat: 'sk-spicy-<48 lowercase hex characters>'
|
|
378
|
+
description: 'Send `Authorization: Bearer sk-spicy-...`. Keep keys server-side.'
|
|
379
|
+
parameters:
|
|
380
|
+
IdempotencyKey:
|
|
381
|
+
name: Idempotency-Key
|
|
382
|
+
in: header
|
|
383
|
+
required: false
|
|
384
|
+
description: Stable key for one logical task submission; retained for 24 hours per account and bound to both the submitting API key and normalized request fingerprint. A sibling key receives 409 without the original task ID.
|
|
385
|
+
schema: { type: string, minLength: 1, maxLength: 128 }
|
|
386
|
+
headers:
|
|
387
|
+
RateLimitLimit:
|
|
388
|
+
description: Capacity of the active account-level rate-limit window.
|
|
389
|
+
schema: { type: integer }
|
|
390
|
+
RateLimitRemaining:
|
|
391
|
+
description: Remaining requests in the active window.
|
|
392
|
+
schema: { type: integer }
|
|
393
|
+
RetryAfter:
|
|
394
|
+
description: Seconds to wait before retrying.
|
|
395
|
+
schema: { type: integer, minimum: 1 }
|
|
396
|
+
responses:
|
|
397
|
+
BadRequest:
|
|
398
|
+
description: Invalid JSON, query, callback URL, model input, or media declaration.
|
|
399
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
400
|
+
Unauthorized:
|
|
401
|
+
description: Missing, malformed, expired, revoked, or otherwise invalid API key.
|
|
402
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
403
|
+
PaymentRequired:
|
|
404
|
+
description: Insufficient balance (`40201`) or a spend cap was reached (`40202`).
|
|
405
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
406
|
+
Forbidden:
|
|
407
|
+
description: Account, model, API-key, IP, or region authorization failed.
|
|
408
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
409
|
+
NotFound:
|
|
410
|
+
description: Resource does not exist or is not visible to this account and API key. These cases are intentionally indistinguishable.
|
|
411
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
412
|
+
Conflict:
|
|
413
|
+
description: Idempotency or media-transfer state conflicts with this request.
|
|
414
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
415
|
+
PayloadTooLarge:
|
|
416
|
+
description: Request body exceeds the server's accepted size limit.
|
|
417
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
418
|
+
RateLimited:
|
|
419
|
+
description: Account-level request limit exceeded.
|
|
420
|
+
headers:
|
|
421
|
+
X-RateLimit-Limit: { $ref: '#/components/headers/RateLimitLimit' }
|
|
422
|
+
X-RateLimit-Remaining: { $ref: '#/components/headers/RateLimitRemaining' }
|
|
423
|
+
Retry-After: { $ref: '#/components/headers/RetryAfter' }
|
|
424
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
425
|
+
ServerError:
|
|
426
|
+
description: Internal failure. Details are not exposed; report `request_id` to support.
|
|
427
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
428
|
+
Unavailable:
|
|
429
|
+
description: No usable deployment or effective customer price exists for the selected model (`50301`).
|
|
430
|
+
content: { application/json: { schema: { $ref: '#/components/schemas/ErrorEnvelope' } } }
|
|
431
|
+
schemas:
|
|
432
|
+
EnvelopeBase:
|
|
433
|
+
type: object
|
|
434
|
+
required: [code, msg, request_id]
|
|
435
|
+
properties:
|
|
436
|
+
code: { type: integer }
|
|
437
|
+
msg: { type: string }
|
|
438
|
+
request_id:
|
|
439
|
+
type: string
|
|
440
|
+
description: Correlation identifier. Include it in support requests.
|
|
441
|
+
ErrorEnvelope:
|
|
442
|
+
allOf:
|
|
443
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
444
|
+
- type: object
|
|
445
|
+
properties:
|
|
446
|
+
code:
|
|
447
|
+
type: integer
|
|
448
|
+
enum: [400, 401, 40201, 40202, 403, 40301, 40302, 40303, 404, 409, 413, 429, 500, 50301]
|
|
449
|
+
msg: { type: string }
|
|
450
|
+
CreateTaskRequest:
|
|
451
|
+
type: object
|
|
452
|
+
required: [model, input]
|
|
453
|
+
additionalProperties: false
|
|
454
|
+
properties:
|
|
455
|
+
model:
|
|
456
|
+
type: string
|
|
457
|
+
minLength: 1
|
|
458
|
+
description: Exact `model` value from the model catalog.
|
|
459
|
+
input:
|
|
460
|
+
type: object
|
|
461
|
+
description: Validated against the selected model's `inputSchema`.
|
|
462
|
+
additionalProperties: true
|
|
463
|
+
callBackUrl:
|
|
464
|
+
type: string
|
|
465
|
+
format: uri
|
|
466
|
+
description: Optional public HTTP(S) endpoint for terminal task delivery.
|
|
467
|
+
mature:
|
|
468
|
+
type: boolean
|
|
469
|
+
default: false
|
|
470
|
+
description: Optional execution metadata passed through to the selected model. The platform applies no account, API-key, model-capability, channel-capability, or content-preflight gate to this field.
|
|
471
|
+
CreateTaskResponse:
|
|
472
|
+
type: object
|
|
473
|
+
required: [taskId, state, estimatedCost]
|
|
474
|
+
properties:
|
|
475
|
+
taskId: { type: string }
|
|
476
|
+
state:
|
|
477
|
+
type: string
|
|
478
|
+
enum: [queued, running, succeeded, failed, canceled, expired]
|
|
479
|
+
description: "`queued` for a new submission; an idempotent replay reports the original task's current state."
|
|
480
|
+
estimatedCost:
|
|
481
|
+
allOf:
|
|
482
|
+
- $ref: '#/components/schemas/USDString'
|
|
483
|
+
description: Funds held when the task is accepted and the maximum amount charged for that task. Unused funds are released; provider overage is absorbed by the platform.
|
|
484
|
+
TaskActionRequest:
|
|
485
|
+
type: object
|
|
486
|
+
required: [taskId]
|
|
487
|
+
additionalProperties: false
|
|
488
|
+
properties:
|
|
489
|
+
taskId: { type: string, minLength: 1 }
|
|
490
|
+
RetryTaskResponse:
|
|
491
|
+
allOf:
|
|
492
|
+
- $ref: '#/components/schemas/CreateTaskResponse'
|
|
493
|
+
- type: object
|
|
494
|
+
required: [sourceTaskId]
|
|
495
|
+
properties:
|
|
496
|
+
sourceTaskId: { type: string }
|
|
497
|
+
RetryTaskEnvelope:
|
|
498
|
+
allOf:
|
|
499
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
500
|
+
- type: object
|
|
501
|
+
required: [data]
|
|
502
|
+
properties:
|
|
503
|
+
code: { type: integer, const: 200 }
|
|
504
|
+
msg: { type: string, const: success }
|
|
505
|
+
data: { $ref: '#/components/schemas/RetryTaskResponse' }
|
|
506
|
+
CreateTaskEnvelope:
|
|
507
|
+
allOf:
|
|
508
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
509
|
+
- type: object
|
|
510
|
+
required: [data]
|
|
511
|
+
properties:
|
|
512
|
+
code: { type: integer, const: 200 }
|
|
513
|
+
msg: { type: string, const: success }
|
|
514
|
+
data: { $ref: '#/components/schemas/CreateTaskResponse' }
|
|
515
|
+
TaskRecord:
|
|
516
|
+
type: object
|
|
517
|
+
required: [taskId, model, state, cost, settled, createdAt]
|
|
518
|
+
properties:
|
|
519
|
+
taskId: { type: string }
|
|
520
|
+
sourceTaskId: { type: string, description: Present when this task was created by explicit retry. }
|
|
521
|
+
model: { type: string }
|
|
522
|
+
state:
|
|
523
|
+
type: string
|
|
524
|
+
enum: [queued, running, succeeded, failed, canceled, expired]
|
|
525
|
+
input:
|
|
526
|
+
description: Normalized model input. Omitted after retention redaction.
|
|
527
|
+
type: object
|
|
528
|
+
additionalProperties: true
|
|
529
|
+
output:
|
|
530
|
+
description: Normalized model output when available. Omitted after retention redaction.
|
|
531
|
+
type: object
|
|
532
|
+
additionalProperties: true
|
|
533
|
+
errorCode: { type: string }
|
|
534
|
+
errorMessage: { type: string }
|
|
535
|
+
cost: { $ref: '#/components/schemas/USDString' }
|
|
536
|
+
settled:
|
|
537
|
+
type: boolean
|
|
538
|
+
description: When false, `cost` is the held estimate. On success the final charge is capped at that hold; unused funds are released. Failed or expired tasks release the hold in full.
|
|
539
|
+
createdAt: { type: string, format: date-time }
|
|
540
|
+
completedAt: { type: string, format: date-time }
|
|
541
|
+
TaskRecordEnvelope:
|
|
542
|
+
allOf:
|
|
543
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
544
|
+
- type: object
|
|
545
|
+
required: [data]
|
|
546
|
+
properties:
|
|
547
|
+
code: { type: integer, const: 200 }
|
|
548
|
+
msg: { type: string, const: success }
|
|
549
|
+
data: { $ref: '#/components/schemas/TaskRecord' }
|
|
550
|
+
LegacyWebhookPayload:
|
|
551
|
+
type: object
|
|
552
|
+
deprecated: true
|
|
553
|
+
description: Version 1 compatibility callback. New integrations must use version 2.
|
|
554
|
+
required: [task_id, model, state, cost, created_at]
|
|
555
|
+
properties:
|
|
556
|
+
task_id: { type: string }
|
|
557
|
+
model: { type: string }
|
|
558
|
+
state: { type: string, enum: [queued, running, succeeded, failed, canceled, expired] }
|
|
559
|
+
output: { type: object, additionalProperties: true }
|
|
560
|
+
error_code: { type: string }
|
|
561
|
+
error_message: { type: string }
|
|
562
|
+
cost: { $ref: '#/components/schemas/USDString' }
|
|
563
|
+
created_at: { type: string, format: date-time }
|
|
564
|
+
Balance:
|
|
565
|
+
type: object
|
|
566
|
+
required: [available, held, total]
|
|
567
|
+
properties:
|
|
568
|
+
available: { $ref: '#/components/schemas/USDString' }
|
|
569
|
+
held: { $ref: '#/components/schemas/USDString' }
|
|
570
|
+
total: { $ref: '#/components/schemas/USDString' }
|
|
571
|
+
BalanceEnvelope:
|
|
572
|
+
allOf:
|
|
573
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
574
|
+
- type: object
|
|
575
|
+
required: [data]
|
|
576
|
+
properties:
|
|
577
|
+
code: { type: integer, const: 200 }
|
|
578
|
+
msg: { type: string, const: success }
|
|
579
|
+
data: { $ref: '#/components/schemas/Balance' }
|
|
580
|
+
APIModelPrice:
|
|
581
|
+
type: object
|
|
582
|
+
required: [variant, unit, price, currency]
|
|
583
|
+
properties:
|
|
584
|
+
variant:
|
|
585
|
+
type: string
|
|
586
|
+
description: Value used by `input.resolution`; empty when the model has one price tier.
|
|
587
|
+
unit: { type: string, enum: [per_image, per_second, per_request, per_1k_tokens] }
|
|
588
|
+
price: { $ref: '#/components/schemas/USDString' }
|
|
589
|
+
currency: { type: string, const: USD }
|
|
590
|
+
APIModel:
|
|
591
|
+
type: object
|
|
592
|
+
required: [model, family, displayName, provider, modality, tasks, async, mature, policyTier, taskTimeoutSeconds, enabled, available, quantityField, pricing, version, availability, badges, relatedModels, updatedAt]
|
|
593
|
+
properties:
|
|
594
|
+
model: { type: string }
|
|
595
|
+
family:
|
|
596
|
+
type: string
|
|
597
|
+
description: Stable product-family identifier; endpoint variants are listed in `tasks` and expressed by `inputSchema`.
|
|
598
|
+
displayName: { type: string }
|
|
599
|
+
provider: { type: string }
|
|
600
|
+
modality: { type: string, enum: [image, video, audio, text] }
|
|
601
|
+
tasks: { type: array, items: { type: string } }
|
|
602
|
+
async: { type: boolean }
|
|
603
|
+
mature:
|
|
604
|
+
type: boolean
|
|
605
|
+
description: Informational model-creator capability metadata only. It does not participate in routing, authorization, or request rejection.
|
|
606
|
+
policyTier:
|
|
607
|
+
type: string
|
|
608
|
+
enum: [unrestricted, borderline, unspecified]
|
|
609
|
+
description: Informational model-creator policy metadata only. It does not participate in routing, authorization, or request rejection.
|
|
610
|
+
taskTimeoutSeconds:
|
|
611
|
+
type: integer
|
|
612
|
+
minimum: 1
|
|
613
|
+
description: Absolute platform execution deadline before timeout/refund; not media output duration.
|
|
614
|
+
maxOutputDurationSeconds:
|
|
615
|
+
type: integer
|
|
616
|
+
minimum: 1
|
|
617
|
+
description: Maximum `input.duration` accepted by the model schema; omitted when the model has no declared duration maximum.
|
|
618
|
+
enabled: { type: boolean }
|
|
619
|
+
available: { type: boolean }
|
|
620
|
+
quantityField: { type: string }
|
|
621
|
+
pricing: { type: array, items: { $ref: '#/components/schemas/APIModelPrice' } }
|
|
622
|
+
startingPrice: { $ref: '#/components/schemas/APIModelPrice' }
|
|
623
|
+
inputSchema:
|
|
624
|
+
type: object
|
|
625
|
+
description: JSON Schema draft 2020-12 used by `createTask.input` validation.
|
|
626
|
+
additionalProperties: true
|
|
627
|
+
version:
|
|
628
|
+
type: string
|
|
629
|
+
description: Provider/model version label used to detect catalog changes.
|
|
630
|
+
availability:
|
|
631
|
+
type: string
|
|
632
|
+
enum: [planned, available, preview, maintenance]
|
|
633
|
+
badges:
|
|
634
|
+
type: array
|
|
635
|
+
description: Closed capability and licensing vocabulary; clients should ignore unknown future IDs.
|
|
636
|
+
items:
|
|
637
|
+
type: string
|
|
638
|
+
enum: [commercial_use, no_watermark, commercial_restricted, reference_input, audio_output, streaming, fast_tier, high_resolution, long_context, mature_capable, policy_unrestricted, policy_borderline]
|
|
639
|
+
relatedModels:
|
|
640
|
+
type: array
|
|
641
|
+
description: Curated model identifiers suitable for alternatives or workflow steps.
|
|
642
|
+
items: { type: string }
|
|
643
|
+
examples:
|
|
644
|
+
type: array
|
|
645
|
+
description: Inputs validated against this model's current input schema.
|
|
646
|
+
items: { $ref: '#/components/schemas/APIModelExample' }
|
|
647
|
+
updatedAt: { type: string, format: date-time }
|
|
648
|
+
APIModelExample:
|
|
649
|
+
type: object
|
|
650
|
+
required: [id, input, sortWeight]
|
|
651
|
+
properties:
|
|
652
|
+
id: { type: string }
|
|
653
|
+
input: { type: object, additionalProperties: true }
|
|
654
|
+
sortWeight: { type: integer }
|
|
655
|
+
APIModelList:
|
|
656
|
+
type: object
|
|
657
|
+
required: [total, items]
|
|
658
|
+
properties:
|
|
659
|
+
total: { type: integer, minimum: 0 }
|
|
660
|
+
items: { type: array, items: { $ref: '#/components/schemas/APIModel' } }
|
|
661
|
+
ModelEnvelope:
|
|
662
|
+
allOf:
|
|
663
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
664
|
+
- type: object
|
|
665
|
+
required: [data]
|
|
666
|
+
properties:
|
|
667
|
+
code: { type: integer, const: 200 }
|
|
668
|
+
msg: { type: string, const: success }
|
|
669
|
+
data: { $ref: '#/components/schemas/APIModel' }
|
|
670
|
+
ModelListEnvelope:
|
|
671
|
+
allOf:
|
|
672
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
673
|
+
- type: object
|
|
674
|
+
required: [data]
|
|
675
|
+
properties:
|
|
676
|
+
code: { type: integer, const: 200 }
|
|
677
|
+
msg: { type: string, const: success }
|
|
678
|
+
data: { $ref: '#/components/schemas/APIModelList' }
|
|
679
|
+
UploadURLRequest:
|
|
680
|
+
type: object
|
|
681
|
+
required: [contentType, bytes]
|
|
682
|
+
additionalProperties: false
|
|
683
|
+
properties:
|
|
684
|
+
contentType: { type: string, enum: [image/jpeg, image/png, image/webp, image/gif] }
|
|
685
|
+
bytes: { type: integer, minimum: 1, maximum: 10485760 }
|
|
686
|
+
UploadURLResponse:
|
|
687
|
+
type: object
|
|
688
|
+
required: [fileId, key, uploadUrl, method, headers, expiresAt, maxBytes]
|
|
689
|
+
properties:
|
|
690
|
+
fileId: { type: string, pattern: '^fil_' }
|
|
691
|
+
key: { type: string, pattern: '^spicy://f/fil_', description: Compatibility alias for the final URI; unusable until commit succeeds. }
|
|
692
|
+
uploadUrl: { type: string, format: uri }
|
|
693
|
+
method: { type: string, const: PUT }
|
|
694
|
+
headers: { type: object, additionalProperties: { type: string } }
|
|
695
|
+
expiresAt: { type: string, format: date-time }
|
|
696
|
+
maxBytes: { type: integer, minimum: 1 }
|
|
697
|
+
UploadURLEnvelope:
|
|
698
|
+
allOf:
|
|
699
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
700
|
+
- type: object
|
|
701
|
+
required: [data]
|
|
702
|
+
properties:
|
|
703
|
+
code: { type: integer, const: 200 }
|
|
704
|
+
msg: { type: string, const: success }
|
|
705
|
+
data: { $ref: '#/components/schemas/UploadURLResponse' }
|
|
706
|
+
FileCommitResponse:
|
|
707
|
+
type: object
|
|
708
|
+
required: [fileId, status, bytes, contentType, sha256, uri, expiresAt]
|
|
709
|
+
properties:
|
|
710
|
+
fileId: { type: string, pattern: '^fil_' }
|
|
711
|
+
status: { type: string, const: ready }
|
|
712
|
+
bytes: { type: integer, minimum: 1 }
|
|
713
|
+
contentType: { type: string, enum: [image/jpeg, image/png, image/webp, image/gif] }
|
|
714
|
+
sha256: { type: string, pattern: '^[a-f0-9]{64}$' }
|
|
715
|
+
uri: { type: string, pattern: '^spicy://f/fil_' }
|
|
716
|
+
expiresAt: { type: string, format: date-time }
|
|
717
|
+
FileCommitEnvelope:
|
|
718
|
+
allOf:
|
|
719
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
720
|
+
- type: object
|
|
721
|
+
required: [data]
|
|
722
|
+
properties:
|
|
723
|
+
code: { type: integer, const: 200 }
|
|
724
|
+
msg: { type: string, const: success }
|
|
725
|
+
data: { $ref: '#/components/schemas/FileCommitResponse' }
|
|
726
|
+
DownloadURLRequest:
|
|
727
|
+
type: object
|
|
728
|
+
required: [taskId]
|
|
729
|
+
additionalProperties: false
|
|
730
|
+
properties:
|
|
731
|
+
taskId: { type: string, minLength: 1 }
|
|
732
|
+
key: { type: string, description: Optional output key; empty selects the first output. }
|
|
733
|
+
DownloadURLResponse:
|
|
734
|
+
type: object
|
|
735
|
+
required: [key, url, expiresAt]
|
|
736
|
+
properties:
|
|
737
|
+
key: { type: string }
|
|
738
|
+
url: { type: string, format: uri }
|
|
739
|
+
expiresAt: { type: string, format: date-time }
|
|
740
|
+
DownloadURLEnvelope:
|
|
741
|
+
allOf:
|
|
742
|
+
- $ref: '#/components/schemas/EnvelopeBase'
|
|
743
|
+
- type: object
|
|
744
|
+
required: [data]
|
|
745
|
+
properties:
|
|
746
|
+
code: { type: integer, const: 200 }
|
|
747
|
+
msg: { type: string, const: success }
|
|
748
|
+
data: { $ref: '#/components/schemas/DownloadURLResponse' }
|
|
749
|
+
USDString:
|
|
750
|
+
type: string
|
|
751
|
+
pattern: '^-?[0-9]+(?:\.[0-9]+)?$'
|
|
752
|
+
description: Decimal USD amount encoded as a string to avoid binary floating-point loss.
|