@fetchmcp-net/cli 0.0.0-stage → 0.0.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/openapi.json ADDED
@@ -0,0 +1,1277 @@
1
+ {
2
+ "openapi": "3.1.0",
3
+ "info": {
4
+ "title": "Live Web Data API",
5
+ "version": "1.0.0",
6
+ "summary": "Live web pages as clean Markdown, text or HTML for AI agents.",
7
+ "description": "Fetch public web pages through our fetch network and get clean Markdown, text or HTML back.\n\nAuthentication: `Authorization: Bearer <api_key>`.\n\n**Per-URL errors** (HTTP 200, in `statuses[].error.tag`, 0 credits): `CRAWL_NOT_FOUND`, `SOURCE_NOT_AVAILABLE`, `CRAWL_LIVECRAWL_TIMEOUT`, `CRAWL_NOT_RENDERED`, `UNSUPPORTED_CONTENT_TYPE`, `CRAWL_UNKNOWN_ERROR`, `SOURCE_BLOCKED`, `BROWSER_UNAVAILABLE`, `RATE_LIMITED`, and `RESTRICTED_TARGET` for blocked URLs inside a multi-URL request.\n\nUp to 10 URLs per request; rate limits count URLs.",
8
+ "contact": {
9
+ "email": "support@livewebdata.com"
10
+ }
11
+ },
12
+ "servers": [
13
+ {
14
+ "url": "https://livewebdata.com/api",
15
+ "description": "Production"
16
+ }
17
+ ],
18
+ "security": [
19
+ {
20
+ "bearerAuth": []
21
+ }
22
+ ],
23
+ "tags": [
24
+ {
25
+ "name": "Contents"
26
+ },
27
+ {
28
+ "name": "Account"
29
+ }
30
+ ],
31
+ "paths": {
32
+ "/v1/contents": {
33
+ "post": {
34
+ "operationId": "getContents",
35
+ "tags": [
36
+ "Contents"
37
+ ],
38
+ "x-cli": {
39
+ "command": "fetch",
40
+ "aliases": [
41
+ "contents"
42
+ ],
43
+ "positional": "urls",
44
+ "output": {
45
+ "items": "results",
46
+ "fields": [
47
+ "markdown",
48
+ "text",
49
+ "html"
50
+ ],
51
+ "heading": "url",
52
+ "errors": "statuses"
53
+ }
54
+ },
55
+ "summary": "Fetch page contents",
56
+ "description": "Fetch 1–10 URLs live and return clean content. HTTP 200 even if individual URLs failed — check `statuses[]`.\n\nA fetch still running after about 100 seconds answers **202** instead: send the same request again with the `Idempotency-Key` from that answer (after `Retry-After` seconds) to get the result. A repeat is not charged again. Results are kept for 15 minutes; a result nobody collects stays charged. Always send your own `Idempotency-Key`: a connection cut after the API received the request (a network error, a timeout, a deploy) can then be retried with the same key without a second charge.",
57
+ "parameters": [
58
+ {
59
+ "name": "Idempotency-Key",
60
+ "in": "header",
61
+ "required": false,
62
+ "description": "Your id for this request, 8–128 characters of `A–Z a–z 0–9 _ - : .`. A repeat with the same key and the same body returns the same result instead of fetching (and charging) again, for 24 hours; with a different body it answers 409. Without it, the API creates one and returns it in the `Idempotency-Key` response header.",
63
+ "schema": {
64
+ "type": "string",
65
+ "pattern": "^[A-Za-z0-9_\\-:.]{8,128}$"
66
+ }
67
+ }
68
+ ],
69
+ "requestBody": {
70
+ "required": true,
71
+ "content": {
72
+ "application/json": {
73
+ "schema": {
74
+ "$ref": "#/components/schemas/ContentsRequest"
75
+ },
76
+ "examples": {
77
+ "single": {
78
+ "summary": "One URL",
79
+ "value": {
80
+ "urls": [
81
+ "https://example.com/article"
82
+ ]
83
+ }
84
+ },
85
+ "options": {
86
+ "summary": "All options",
87
+ "value": {
88
+ "urls": [
89
+ "https://example.com/article"
90
+ ],
91
+ "countryCode": "de",
92
+ "text": {
93
+ "maxCharacters": 50000,
94
+ "verbosity": "compact"
95
+ },
96
+ "livecrawlTimeout": 15000
97
+ }
98
+ },
99
+ "multi": {
100
+ "summary": "Several URLs (one restricted)",
101
+ "value": {
102
+ "urls": [
103
+ "https://example.com/a",
104
+ "https://example.com/b",
105
+ "https://example.com/blocked"
106
+ ]
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ },
113
+ "responses": {
114
+ "200": {
115
+ "description": "Processed. One status per URL; successful pages in results.",
116
+ "headers": {
117
+ "X-Request-Id": {
118
+ "description": "Same as requestId in the body.",
119
+ "schema": {
120
+ "type": "string"
121
+ }
122
+ },
123
+ "X-Credits-Remaining": {
124
+ "description": "Credit balance after this request.",
125
+ "schema": {
126
+ "type": "integer"
127
+ }
128
+ },
129
+ "X-RateLimit-Limit": {
130
+ "description": "URLs you can send at once (bucket size, = rateLimit.burst in GET /v1/account). The bucket refills at rateLimit.requestsPerSecond URLs per second.",
131
+ "schema": {
132
+ "type": "integer"
133
+ }
134
+ },
135
+ "X-RateLimit-Remaining": {
136
+ "description": "URLs you can send right now.",
137
+ "schema": {
138
+ "type": "integer"
139
+ }
140
+ },
141
+ "Idempotency-Key": {
142
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
143
+ "schema": {
144
+ "type": "string"
145
+ }
146
+ }
147
+ },
148
+ "content": {
149
+ "application/json": {
150
+ "schema": {
151
+ "$ref": "#/components/schemas/ContentsResponse"
152
+ },
153
+ "example": {
154
+ "requestId": "req_01JEXAMPLE0000000000000",
155
+ "results": [
156
+ {
157
+ "id": "https://example.com/article",
158
+ "url": "https://example.com/article",
159
+ "title": "Article",
160
+ "author": null,
161
+ "publishedDate": null,
162
+ "image": null,
163
+ "favicon": "https://example.com/favicon.ico",
164
+ "markdown": "# Article\n\n…",
165
+ "text": "Article\n\n…",
166
+ "html": "<!doctype html>…"
167
+ }
168
+ ],
169
+ "statuses": [
170
+ {
171
+ "id": "https://example.com/article",
172
+ "status": "success",
173
+ "source": "livecrawled",
174
+ "httpStatusCode": 200,
175
+ "strategy": "fast",
176
+ "credits": 1,
177
+ "error": null
178
+ }
179
+ ],
180
+ "searchTime": 1240
181
+ }
182
+ }
183
+ }
184
+ },
185
+ "202": {
186
+ "description": "Still fetching after about 100 seconds. Send the same request again with this Idempotency-Key after Retry-After seconds; the repeat waits for the result and is not charged again.",
187
+ "headers": {
188
+ "X-Request-Id": {
189
+ "description": "Same as requestId in the body.",
190
+ "schema": {
191
+ "type": "string"
192
+ }
193
+ },
194
+ "Retry-After": {
195
+ "description": "Seconds to wait: before retrying a 429, or before repeating a 202 with the same Idempotency-Key.",
196
+ "schema": {
197
+ "type": "integer"
198
+ }
199
+ },
200
+ "Idempotency-Key": {
201
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
202
+ "schema": {
203
+ "type": "string"
204
+ }
205
+ }
206
+ },
207
+ "content": {
208
+ "application/json": {
209
+ "schema": {
210
+ "$ref": "#/components/schemas/Pending"
211
+ },
212
+ "example": {
213
+ "status": "pending",
214
+ "requestId": "req_01JEXAMPLE0000000000000",
215
+ "idempotencyKey": "lwda_3f1c2b7e-0d4a-4c1e-9a55-2b8f0e6c7d10",
216
+ "retryAfter": 1,
217
+ "message": "Still fetching. Send the same request again with the same Idempotency-Key header to get the result; it is not charged again."
218
+ }
219
+ }
220
+ }
221
+ },
222
+ "400": {
223
+ "description": "INVALID_REQUEST: Invalid parameters. TOO_MANY_URLS: More URLs than allowed per request (10). FREE_TIER_SINGLE_URL: Free test: one URL per request. Upgrade for up to 10.",
224
+ "headers": {
225
+ "X-Request-Id": {
226
+ "description": "Same as requestId in the body.",
227
+ "schema": {
228
+ "type": "string"
229
+ }
230
+ },
231
+ "Idempotency-Key": {
232
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
233
+ "schema": {
234
+ "type": "string"
235
+ }
236
+ }
237
+ },
238
+ "content": {
239
+ "application/json": {
240
+ "schema": {
241
+ "$ref": "#/components/schemas/Error"
242
+ },
243
+ "examples": {
244
+ "INVALID_REQUEST": {
245
+ "value": {
246
+ "error": {
247
+ "code": 400,
248
+ "tag": "INVALID_REQUEST",
249
+ "message": "Invalid parameters."
250
+ },
251
+ "requestId": "req_01JEXAMPLE0000000000000"
252
+ }
253
+ },
254
+ "TOO_MANY_URLS": {
255
+ "value": {
256
+ "error": {
257
+ "code": 400,
258
+ "tag": "TOO_MANY_URLS",
259
+ "message": "More URLs than allowed per request (10)."
260
+ },
261
+ "requestId": "req_01JEXAMPLE0000000000000"
262
+ }
263
+ },
264
+ "FREE_TIER_SINGLE_URL": {
265
+ "value": {
266
+ "error": {
267
+ "code": 400,
268
+ "tag": "FREE_TIER_SINGLE_URL",
269
+ "message": "Free test: one URL per request. Upgrade for up to 10."
270
+ },
271
+ "requestId": "req_01JEXAMPLE0000000000000"
272
+ }
273
+ }
274
+ }
275
+ }
276
+ }
277
+ },
278
+ "401": {
279
+ "description": "UNAUTHORIZED: Missing or invalid API key.",
280
+ "headers": {
281
+ "X-Request-Id": {
282
+ "description": "Same as requestId in the body.",
283
+ "schema": {
284
+ "type": "string"
285
+ }
286
+ },
287
+ "Idempotency-Key": {
288
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
289
+ "schema": {
290
+ "type": "string"
291
+ }
292
+ }
293
+ },
294
+ "content": {
295
+ "application/json": {
296
+ "schema": {
297
+ "$ref": "#/components/schemas/Error"
298
+ },
299
+ "examples": {
300
+ "UNAUTHORIZED": {
301
+ "value": {
302
+ "error": {
303
+ "code": 401,
304
+ "tag": "UNAUTHORIZED",
305
+ "message": "Missing or invalid API key."
306
+ },
307
+ "requestId": "req_01JEXAMPLE0000000000000"
308
+ }
309
+ }
310
+ }
311
+ }
312
+ }
313
+ },
314
+ "402": {
315
+ "description": "INSUFFICIENT_CREDITS: Not enough credits. Top up or upgrade. On the free test the body adds nextResetAt and freeTierEnded.",
316
+ "headers": {
317
+ "X-Request-Id": {
318
+ "description": "Same as requestId in the body.",
319
+ "schema": {
320
+ "type": "string"
321
+ }
322
+ },
323
+ "Idempotency-Key": {
324
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
325
+ "schema": {
326
+ "type": "string"
327
+ }
328
+ }
329
+ },
330
+ "content": {
331
+ "application/json": {
332
+ "schema": {
333
+ "$ref": "#/components/schemas/Error"
334
+ },
335
+ "examples": {
336
+ "INSUFFICIENT_CREDITS": {
337
+ "value": {
338
+ "error": {
339
+ "code": 402,
340
+ "tag": "INSUFFICIENT_CREDITS",
341
+ "message": "Not enough credits. Top up or upgrade. On the free test the body adds nextResetAt and freeTierEnded."
342
+ },
343
+ "requestId": "req_01JEXAMPLE0000000000000"
344
+ }
345
+ }
346
+ }
347
+ }
348
+ }
349
+ },
350
+ "403": {
351
+ "description": "KEY_SUSPENDED: The key or account is suspended or not yet approved. FREE_TIER_FEATURE: Free test: this feature is available on paid plans.",
352
+ "headers": {
353
+ "X-Request-Id": {
354
+ "description": "Same as requestId in the body.",
355
+ "schema": {
356
+ "type": "string"
357
+ }
358
+ },
359
+ "Idempotency-Key": {
360
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
361
+ "schema": {
362
+ "type": "string"
363
+ }
364
+ }
365
+ },
366
+ "content": {
367
+ "application/json": {
368
+ "schema": {
369
+ "$ref": "#/components/schemas/Error"
370
+ },
371
+ "examples": {
372
+ "KEY_SUSPENDED": {
373
+ "value": {
374
+ "error": {
375
+ "code": 403,
376
+ "tag": "KEY_SUSPENDED",
377
+ "message": "The key or account is suspended or not yet approved."
378
+ },
379
+ "requestId": "req_01JEXAMPLE0000000000000"
380
+ }
381
+ },
382
+ "FREE_TIER_FEATURE": {
383
+ "value": {
384
+ "error": {
385
+ "code": 403,
386
+ "tag": "FREE_TIER_FEATURE",
387
+ "message": "Free test: this feature is available on paid plans."
388
+ },
389
+ "requestId": "req_01JEXAMPLE0000000000000"
390
+ }
391
+ }
392
+ }
393
+ }
394
+ }
395
+ },
396
+ "409": {
397
+ "description": "IDEMPOTENCY_CONFLICT: The Idempotency-Key was already used with a different request, or its result is no longer available (results are kept 15 minutes). Use a new key.",
398
+ "headers": {
399
+ "X-Request-Id": {
400
+ "description": "Same as requestId in the body.",
401
+ "schema": {
402
+ "type": "string"
403
+ }
404
+ },
405
+ "Idempotency-Key": {
406
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
407
+ "schema": {
408
+ "type": "string"
409
+ }
410
+ }
411
+ },
412
+ "content": {
413
+ "application/json": {
414
+ "schema": {
415
+ "$ref": "#/components/schemas/Error"
416
+ },
417
+ "examples": {
418
+ "IDEMPOTENCY_CONFLICT": {
419
+ "value": {
420
+ "error": {
421
+ "code": 409,
422
+ "tag": "IDEMPOTENCY_CONFLICT",
423
+ "message": "The Idempotency-Key was already used with a different request, or its result is no longer available (results are kept 15 minutes). Use a new key."
424
+ },
425
+ "requestId": "req_01JEXAMPLE0000000000000"
426
+ }
427
+ }
428
+ }
429
+ }
430
+ }
431
+ },
432
+ "413": {
433
+ "description": "PAYLOAD_TOO_LARGE: The request body is larger than 10 MiB. Nothing was read or charged.",
434
+ "headers": {
435
+ "X-Request-Id": {
436
+ "description": "Same as requestId in the body.",
437
+ "schema": {
438
+ "type": "string"
439
+ }
440
+ }
441
+ },
442
+ "content": {
443
+ "application/json": {
444
+ "schema": {
445
+ "$ref": "#/components/schemas/Error"
446
+ },
447
+ "examples": {
448
+ "PAYLOAD_TOO_LARGE": {
449
+ "value": {
450
+ "error": {
451
+ "code": 413,
452
+ "tag": "PAYLOAD_TOO_LARGE",
453
+ "message": "The request body is larger than 10 MiB. Nothing was read or charged."
454
+ },
455
+ "requestId": "req_01JEXAMPLE0000000000000"
456
+ }
457
+ }
458
+ }
459
+ }
460
+ }
461
+ },
462
+ "429": {
463
+ "description": "RATE_LIMITED: Rate limit exceeded. Retry after the Retry-After header.",
464
+ "headers": {
465
+ "X-Request-Id": {
466
+ "description": "Same as requestId in the body.",
467
+ "schema": {
468
+ "type": "string"
469
+ }
470
+ },
471
+ "X-RateLimit-Limit": {
472
+ "description": "URLs you can send at once (bucket size, = rateLimit.burst in GET /v1/account). The bucket refills at rateLimit.requestsPerSecond URLs per second.",
473
+ "schema": {
474
+ "type": "integer"
475
+ }
476
+ },
477
+ "X-RateLimit-Remaining": {
478
+ "description": "URLs you can send right now.",
479
+ "schema": {
480
+ "type": "integer"
481
+ }
482
+ },
483
+ "Retry-After": {
484
+ "description": "Seconds to wait: before retrying a 429, or before repeating a 202 with the same Idempotency-Key.",
485
+ "schema": {
486
+ "type": "integer"
487
+ }
488
+ },
489
+ "Idempotency-Key": {
490
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
491
+ "schema": {
492
+ "type": "string"
493
+ }
494
+ }
495
+ },
496
+ "content": {
497
+ "application/json": {
498
+ "schema": {
499
+ "$ref": "#/components/schemas/Error"
500
+ },
501
+ "examples": {
502
+ "RATE_LIMITED": {
503
+ "value": {
504
+ "error": {
505
+ "code": 429,
506
+ "tag": "RATE_LIMITED",
507
+ "message": "Rate limit exceeded. Retry after the Retry-After header."
508
+ },
509
+ "requestId": "req_01JEXAMPLE0000000000000"
510
+ }
511
+ }
512
+ }
513
+ }
514
+ }
515
+ },
516
+ "451": {
517
+ "description": "RESTRICTED_TARGET: All requested URLs are restricted. No credits charged.",
518
+ "headers": {
519
+ "X-Request-Id": {
520
+ "description": "Same as requestId in the body.",
521
+ "schema": {
522
+ "type": "string"
523
+ }
524
+ },
525
+ "Idempotency-Key": {
526
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
527
+ "schema": {
528
+ "type": "string"
529
+ }
530
+ }
531
+ },
532
+ "content": {
533
+ "application/json": {
534
+ "schema": {
535
+ "$ref": "#/components/schemas/Error"
536
+ },
537
+ "examples": {
538
+ "RESTRICTED_TARGET": {
539
+ "value": {
540
+ "error": {
541
+ "code": 451,
542
+ "tag": "RESTRICTED_TARGET",
543
+ "message": "All requested URLs are restricted. No credits charged."
544
+ },
545
+ "requestId": "req_01JEXAMPLE0000000000000"
546
+ }
547
+ }
548
+ }
549
+ }
550
+ }
551
+ },
552
+ "503": {
553
+ "description": "SERVICE_UNAVAILABLE: Temporarily unavailable. Retry shortly.",
554
+ "headers": {
555
+ "X-Request-Id": {
556
+ "description": "Same as requestId in the body.",
557
+ "schema": {
558
+ "type": "string"
559
+ }
560
+ },
561
+ "Idempotency-Key": {
562
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
563
+ "schema": {
564
+ "type": "string"
565
+ }
566
+ }
567
+ },
568
+ "content": {
569
+ "application/json": {
570
+ "schema": {
571
+ "$ref": "#/components/schemas/Error"
572
+ },
573
+ "examples": {
574
+ "SERVICE_UNAVAILABLE": {
575
+ "value": {
576
+ "error": {
577
+ "code": 503,
578
+ "tag": "SERVICE_UNAVAILABLE",
579
+ "message": "Temporarily unavailable. Retry shortly."
580
+ },
581
+ "requestId": "req_01JEXAMPLE0000000000000"
582
+ }
583
+ }
584
+ }
585
+ }
586
+ }
587
+ }
588
+ }
589
+ }
590
+ },
591
+ "/v1/account": {
592
+ "get": {
593
+ "operationId": "getAccount",
594
+ "tags": [
595
+ "Account"
596
+ ],
597
+ "x-cli": {
598
+ "command": "account"
599
+ },
600
+ "summary": "Get account status",
601
+ "description": "Plan, remaining credits and rate limit for the calling key. Free. Use before large batches.",
602
+ "responses": {
603
+ "200": {
604
+ "description": "Account summary.",
605
+ "content": {
606
+ "application/json": {
607
+ "schema": {
608
+ "$ref": "#/components/schemas/Account"
609
+ },
610
+ "example": {
611
+ "plan": "starter",
612
+ "status": "active",
613
+ "credits": {
614
+ "plan": 81234,
615
+ "topup": 10000,
616
+ "total": 91234
617
+ },
618
+ "rateLimit": {
619
+ "requestsPerSecond": 2,
620
+ "burst": 4
621
+ },
622
+ "periodEndsAt": "2026-11-01T00:00:00Z"
623
+ }
624
+ }
625
+ }
626
+ },
627
+ "401": {
628
+ "description": "UNAUTHORIZED: Missing or invalid API key.",
629
+ "headers": {
630
+ "X-Request-Id": {
631
+ "description": "Same as requestId in the body.",
632
+ "schema": {
633
+ "type": "string"
634
+ }
635
+ },
636
+ "Idempotency-Key": {
637
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
638
+ "schema": {
639
+ "type": "string"
640
+ }
641
+ }
642
+ },
643
+ "content": {
644
+ "application/json": {
645
+ "schema": {
646
+ "$ref": "#/components/schemas/Error"
647
+ },
648
+ "examples": {
649
+ "UNAUTHORIZED": {
650
+ "value": {
651
+ "error": {
652
+ "code": 401,
653
+ "tag": "UNAUTHORIZED",
654
+ "message": "Missing or invalid API key."
655
+ },
656
+ "requestId": "req_01JEXAMPLE0000000000000"
657
+ }
658
+ }
659
+ }
660
+ }
661
+ }
662
+ },
663
+ "403": {
664
+ "description": "KEY_SUSPENDED: The key or account is suspended or not yet approved. FREE_TIER_FEATURE: Free test: this feature is available on paid plans.",
665
+ "headers": {
666
+ "X-Request-Id": {
667
+ "description": "Same as requestId in the body.",
668
+ "schema": {
669
+ "type": "string"
670
+ }
671
+ },
672
+ "Idempotency-Key": {
673
+ "description": "The request's Idempotency-Key: yours, or one the API created when you sent none. On every answer (200, 202, errors) except a 400 for a malformed key and a 413 for a body over 10 MiB (refused unread). Repeat a 202 with it.",
674
+ "schema": {
675
+ "type": "string"
676
+ }
677
+ }
678
+ },
679
+ "content": {
680
+ "application/json": {
681
+ "schema": {
682
+ "$ref": "#/components/schemas/Error"
683
+ },
684
+ "examples": {
685
+ "KEY_SUSPENDED": {
686
+ "value": {
687
+ "error": {
688
+ "code": 403,
689
+ "tag": "KEY_SUSPENDED",
690
+ "message": "The key or account is suspended or not yet approved."
691
+ },
692
+ "requestId": "req_01JEXAMPLE0000000000000"
693
+ }
694
+ },
695
+ "FREE_TIER_FEATURE": {
696
+ "value": {
697
+ "error": {
698
+ "code": 403,
699
+ "tag": "FREE_TIER_FEATURE",
700
+ "message": "Free test: this feature is available on paid plans."
701
+ },
702
+ "requestId": "req_01JEXAMPLE0000000000000"
703
+ }
704
+ }
705
+ }
706
+ }
707
+ }
708
+ }
709
+ }
710
+ }
711
+ }
712
+ },
713
+ "components": {
714
+ "securitySchemes": {
715
+ "bearerAuth": {
716
+ "type": "http",
717
+ "scheme": "bearer",
718
+ "description": "API key, e.g. 1337_live_…"
719
+ }
720
+ },
721
+ "schemas": {
722
+ "ContentsRequest": {
723
+ "type": "object",
724
+ "properties": {
725
+ "urls": {
726
+ "minItems": 1,
727
+ "maxItems": 10,
728
+ "type": "array",
729
+ "items": {
730
+ "type": "string",
731
+ "maxLength": 8192,
732
+ "format": "uri"
733
+ },
734
+ "description": "Pages to fetch (1–10), each at most 8,192 characters. Processed in parallel; one entry per URL in statuses. Duplicates (same URL, ignoring #fragment) are fetched once; repeated positions cost 0 credits."
735
+ },
736
+ "countryCode": {
737
+ "description": "ISO-3166-1 alpha-2 country to fetch from. Default \"us\".",
738
+ "type": "string",
739
+ "minLength": 2,
740
+ "maxLength": 2
741
+ },
742
+ "text": {
743
+ "description": "Content options. Default enabled.",
744
+ "anyOf": [
745
+ {
746
+ "type": "boolean"
747
+ },
748
+ {
749
+ "type": "object",
750
+ "properties": {
751
+ "maxCharacters": {
752
+ "description": "Truncate text and markdown to this many characters. Default 100000. results[].textTruncated tells you when it did.",
753
+ "type": "integer",
754
+ "minimum": 1,
755
+ "maximum": 1000000
756
+ },
757
+ "verbosity": {
758
+ "description": "\"compact\" = main content (default), \"full\" = whole body.",
759
+ "type": "string",
760
+ "enum": [
761
+ "compact",
762
+ "full"
763
+ ]
764
+ }
765
+ },
766
+ "additionalProperties": false
767
+ }
768
+ ]
769
+ },
770
+ "maxAgeHours": {
771
+ "description": "Accepted only as 0 (for older clients): there is no cache, every request is fetched live.",
772
+ "type": "number",
773
+ "const": 0
774
+ },
775
+ "html": {
776
+ "description": "Include the page HTML as served in results[].html. Default false. A response carries at most 24 MiB of JSON: past that, the remaining results come without html (warning RESPONSE_SIZE_LIMIT).",
777
+ "type": "boolean"
778
+ },
779
+ "livecrawlTimeout": {
780
+ "description": "Live fetch timeout in ms (1–90000). Default 60000, and a value below 30000 is raised to 30000 (the browser fallback needs it); with renderFallback: false any value, default 10000; with render or renderFallback: true at least 30000, default 60000.",
781
+ "type": "integer",
782
+ "minimum": 1,
783
+ "maximum": 90000
784
+ },
785
+ "render": {
786
+ "description": "Render every URL in a real browser, as a normal visitor sees it (3 credits, 5 when the page needed a retry through another connection). Cannot be combined with renderFallback. Default false.",
787
+ "type": "boolean"
788
+ },
789
+ "renderFallback": {
790
+ "description": "Fetch normally first; render in a real browser only when the first attempt did not return the page or shows no or very little visible text. On by default (omit it); false = plain fetch only, never a browser. A normal success costs its normal credits, a rendered one only the render credits. Cannot be combined with render: true.",
791
+ "type": "boolean"
792
+ }
793
+ },
794
+ "required": [
795
+ "urls"
796
+ ],
797
+ "additionalProperties": false
798
+ },
799
+ "ContentsResponse": {
800
+ "type": "object",
801
+ "properties": {
802
+ "requestId": {
803
+ "type": "string"
804
+ },
805
+ "results": {
806
+ "type": "array",
807
+ "items": {
808
+ "$ref": "#/components/schemas/ContentsResult"
809
+ },
810
+ "description": "One entry per successfully fetched URL."
811
+ },
812
+ "statuses": {
813
+ "type": "array",
814
+ "items": {
815
+ "$ref": "#/components/schemas/ContentsStatus"
816
+ },
817
+ "description": "One entry per requested URL."
818
+ },
819
+ "searchTime": {
820
+ "type": "integer",
821
+ "minimum": -9007199254740991,
822
+ "maximum": 9007199254740991,
823
+ "description": "Processing time in ms."
824
+ }
825
+ },
826
+ "required": [
827
+ "requestId",
828
+ "results",
829
+ "statuses",
830
+ "searchTime"
831
+ ]
832
+ },
833
+ "ContentsResult": {
834
+ "type": "object",
835
+ "properties": {
836
+ "id": {
837
+ "type": "string",
838
+ "description": "The requested URL (matches statuses[].id)."
839
+ },
840
+ "url": {
841
+ "type": "string",
842
+ "description": "Final URL after redirects."
843
+ },
844
+ "title": {
845
+ "description": "At most 2,000 characters (cut with an ellipsis).",
846
+ "type": [
847
+ "string",
848
+ "null"
849
+ ]
850
+ },
851
+ "author": {
852
+ "description": "At most 2,000 characters (cut with an ellipsis).",
853
+ "type": [
854
+ "string",
855
+ "null"
856
+ ]
857
+ },
858
+ "publishedDate": {
859
+ "type": [
860
+ "string",
861
+ "null"
862
+ ]
863
+ },
864
+ "image": {
865
+ "description": "null when the page names none, or a URL longer than 4,096 characters.",
866
+ "type": [
867
+ "string",
868
+ "null"
869
+ ]
870
+ },
871
+ "favicon": {
872
+ "description": "The page's icon, else /favicon.ico of its origin (an icon URL longer than 4,096 characters is not used).",
873
+ "type": [
874
+ "string",
875
+ "null"
876
+ ]
877
+ },
878
+ "text": {
879
+ "description": "Plain text, tags removed, whitespace normalized.",
880
+ "type": "string"
881
+ },
882
+ "markdown": {
883
+ "description": "Main content as Markdown.",
884
+ "type": "string"
885
+ },
886
+ "html": {
887
+ "description": "Page HTML as served. Only with html: true, and only while the response stays within its 24 MiB size limit (else warning RESPONSE_SIZE_LIMIT).",
888
+ "type": "string"
889
+ },
890
+ "textTruncated": {
891
+ "description": "true when text or markdown was cut at text.maxCharacters, or at the response size limit (warning RESPONSE_SIZE_LIMIT). Present whenever text is enabled.",
892
+ "type": "boolean"
893
+ },
894
+ "warnings": {
895
+ "description": "Absent when empty. \"PAGE_TRUNCATED\" = only part of the page could be retrieved; \"THIN_CONTENT\" = the page probably needs render: true; \"EXTRACTION_FALLBACK\" = converted as plain text (too complex in time); \"RESPONSE_SIZE_LIMIT\" = the response reached its 24 MiB size limit, so this result has no html (and maybe cut text/markdown).",
896
+ "type": "array",
897
+ "items": {
898
+ "type": "object",
899
+ "properties": {
900
+ "code": {
901
+ "type": "string",
902
+ "enum": [
903
+ "PAGE_TRUNCATED",
904
+ "THIN_CONTENT",
905
+ "EXTRACTION_FALLBACK",
906
+ "RESPONSE_SIZE_LIMIT"
907
+ ]
908
+ },
909
+ "message": {
910
+ "type": "string"
911
+ }
912
+ },
913
+ "required": [
914
+ "code",
915
+ "message"
916
+ ]
917
+ }
918
+ }
919
+ },
920
+ "required": [
921
+ "id",
922
+ "url",
923
+ "title",
924
+ "author",
925
+ "publishedDate",
926
+ "image",
927
+ "favicon"
928
+ ]
929
+ },
930
+ "ContentsStatus": {
931
+ "type": "object",
932
+ "properties": {
933
+ "id": {
934
+ "type": "string"
935
+ },
936
+ "status": {
937
+ "type": "string",
938
+ "enum": [
939
+ "success",
940
+ "error"
941
+ ]
942
+ },
943
+ "source": {
944
+ "anyOf": [
945
+ {
946
+ "type": "string",
947
+ "enum": [
948
+ "livecrawled",
949
+ "cached",
950
+ "cached-fallback"
951
+ ]
952
+ },
953
+ {
954
+ "type": "null"
955
+ }
956
+ ],
957
+ "description": "Always \"livecrawled\" on success (there is no cache); null on error."
958
+ },
959
+ "fetchedAt": {
960
+ "description": "When the page was fetched (ISO 8601); null on error.",
961
+ "type": [
962
+ "string",
963
+ "null"
964
+ ]
965
+ },
966
+ "httpStatusCode": {
967
+ "anyOf": [
968
+ {
969
+ "type": "integer",
970
+ "minimum": -9007199254740991,
971
+ "maximum": 9007199254740991
972
+ },
973
+ {
974
+ "type": "null"
975
+ }
976
+ ]
977
+ },
978
+ "strategy": {
979
+ "type": "string",
980
+ "enum": [
981
+ "fast",
982
+ "retry",
983
+ "browser",
984
+ "local-browser"
985
+ ],
986
+ "description": "\"fast\" = standard fetch (1 credit). \"retry\" = the first attempt did not return the page, a retry through another connection did (2 credits). \"browser\" = rendered in a real browser, as a normal visitor sees it (3 credits, 5 when it needed a retry through another connection). \"local-browser\" is reserved."
987
+ },
988
+ "credits": {
989
+ "type": "integer",
990
+ "minimum": -9007199254740991,
991
+ "maximum": 9007199254740991,
992
+ "description": "Credits charged for this URL: 1 standard, 2 retried, 3 rendered, 5 rendered + retried, 0 on error and for a short page delivered with thin: true (a success, not an error)."
993
+ },
994
+ "fallbackUsed": {
995
+ "description": "Present (true) only when the browser fallback ran for this URL: with strategy \"browser\" the content is that render (fast → render); with another strategy, or on error, rendering was tried and did not help.",
996
+ "type": "boolean"
997
+ },
998
+ "thin": {
999
+ "description": "Present (true) only for a short page delivered at 0 credits: fewer than 500 characters of visible text even after rendering. The result holds only that visible text. A success, not an error.",
1000
+ "type": "boolean"
1001
+ },
1002
+ "error": {
1003
+ "anyOf": [
1004
+ {
1005
+ "type": "object",
1006
+ "properties": {
1007
+ "tag": {
1008
+ "type": "string",
1009
+ "enum": [
1010
+ "CRAWL_NOT_FOUND",
1011
+ "SOURCE_NOT_AVAILABLE",
1012
+ "CRAWL_LIVECRAWL_TIMEOUT",
1013
+ "CRAWL_NOT_RENDERED",
1014
+ "UNSUPPORTED_CONTENT_TYPE",
1015
+ "CRAWL_UNKNOWN_ERROR",
1016
+ "SOURCE_BLOCKED",
1017
+ "BROWSER_UNAVAILABLE",
1018
+ "RATE_LIMITED",
1019
+ "RESTRICTED_TARGET"
1020
+ ]
1021
+ },
1022
+ "message": {
1023
+ "type": "string"
1024
+ }
1025
+ },
1026
+ "required": [
1027
+ "tag",
1028
+ "message"
1029
+ ]
1030
+ },
1031
+ {
1032
+ "type": "null"
1033
+ }
1034
+ ]
1035
+ }
1036
+ },
1037
+ "required": [
1038
+ "id",
1039
+ "status",
1040
+ "source",
1041
+ "fetchedAt",
1042
+ "httpStatusCode",
1043
+ "strategy",
1044
+ "credits",
1045
+ "error"
1046
+ ]
1047
+ },
1048
+ "Error": {
1049
+ "type": "object",
1050
+ "properties": {
1051
+ "error": {
1052
+ "type": "object",
1053
+ "properties": {
1054
+ "code": {
1055
+ "type": "integer",
1056
+ "minimum": -9007199254740991,
1057
+ "maximum": 9007199254740991
1058
+ },
1059
+ "tag": {
1060
+ "type": "string",
1061
+ "enum": [
1062
+ "INVALID_REQUEST",
1063
+ "TOO_MANY_URLS",
1064
+ "UNAUTHORIZED",
1065
+ "INSUFFICIENT_CREDITS",
1066
+ "KEY_SUSPENDED",
1067
+ "RATE_LIMITED",
1068
+ "RESTRICTED_TARGET",
1069
+ "IDEMPOTENCY_CONFLICT",
1070
+ "PAYLOAD_TOO_LARGE",
1071
+ "SERVICE_UNAVAILABLE",
1072
+ "FREE_TIER_SINGLE_URL",
1073
+ "FREE_TIER_FEATURE"
1074
+ ]
1075
+ },
1076
+ "message": {
1077
+ "type": "string"
1078
+ },
1079
+ "nextResetAt": {
1080
+ "description": "Free test, 402 only: when this week's credits come back (Monday 00:00 UTC).",
1081
+ "type": [
1082
+ "string",
1083
+ "null"
1084
+ ]
1085
+ },
1086
+ "freeTierEnded": {
1087
+ "description": "Free test, 402 only: true once the 4 weeks are over.",
1088
+ "type": "boolean"
1089
+ },
1090
+ "upgradeUrl": {
1091
+ "description": "Free test, 402 only: where to choose a plan.",
1092
+ "type": "string"
1093
+ }
1094
+ },
1095
+ "required": [
1096
+ "code",
1097
+ "tag",
1098
+ "message"
1099
+ ]
1100
+ },
1101
+ "requestId": {
1102
+ "type": "string"
1103
+ }
1104
+ },
1105
+ "required": [
1106
+ "error",
1107
+ "requestId"
1108
+ ]
1109
+ },
1110
+ "Pending": {
1111
+ "type": "object",
1112
+ "properties": {
1113
+ "status": {
1114
+ "type": "string",
1115
+ "const": "pending"
1116
+ },
1117
+ "requestId": {
1118
+ "type": "string",
1119
+ "description": "Same for every repeat with the same Idempotency-Key."
1120
+ },
1121
+ "idempotencyKey": {
1122
+ "type": "string",
1123
+ "description": "Send the same request again with this Idempotency-Key header."
1124
+ },
1125
+ "retryAfter": {
1126
+ "type": "integer",
1127
+ "minimum": -9007199254740991,
1128
+ "maximum": 9007199254740991,
1129
+ "description": "Seconds to wait before repeating (also the Retry-After header)."
1130
+ },
1131
+ "message": {
1132
+ "type": "string"
1133
+ }
1134
+ },
1135
+ "required": [
1136
+ "status",
1137
+ "requestId",
1138
+ "idempotencyKey",
1139
+ "retryAfter",
1140
+ "message"
1141
+ ]
1142
+ },
1143
+ "Account": {
1144
+ "type": "object",
1145
+ "properties": {
1146
+ "plan": {
1147
+ "type": "string",
1148
+ "description": "Plan id, e.g. \"starter\" (\"trial\" before a plan is activated)."
1149
+ },
1150
+ "status": {
1151
+ "type": "string",
1152
+ "description": "Account status, e.g. active, pending_review, suspended."
1153
+ },
1154
+ "credits": {
1155
+ "type": "object",
1156
+ "properties": {
1157
+ "plan": {
1158
+ "type": "integer",
1159
+ "minimum": -9007199254740991,
1160
+ "maximum": 9007199254740991
1161
+ },
1162
+ "topup": {
1163
+ "type": "integer",
1164
+ "minimum": -9007199254740991,
1165
+ "maximum": 9007199254740991
1166
+ },
1167
+ "total": {
1168
+ "type": "integer",
1169
+ "minimum": -9007199254740991,
1170
+ "maximum": 9007199254740991
1171
+ }
1172
+ },
1173
+ "required": [
1174
+ "plan",
1175
+ "topup",
1176
+ "total"
1177
+ ]
1178
+ },
1179
+ "rateLimit": {
1180
+ "type": "object",
1181
+ "properties": {
1182
+ "requestsPerSecond": {
1183
+ "type": "number",
1184
+ "description": "Refill rate: URLs per second, sustained."
1185
+ },
1186
+ "burst": {
1187
+ "type": "integer",
1188
+ "minimum": -9007199254740991,
1189
+ "maximum": 9007199254740991,
1190
+ "description": "Bucket size: URLs you can send at once. Same number as the X-RateLimit-Limit header."
1191
+ }
1192
+ },
1193
+ "required": [
1194
+ "requestsPerSecond",
1195
+ "burst"
1196
+ ]
1197
+ },
1198
+ "periodEndsAt": {
1199
+ "description": "End of the current billing period (ISO 8601).",
1200
+ "type": [
1201
+ "string",
1202
+ "null"
1203
+ ]
1204
+ },
1205
+ "freeTest": {
1206
+ "description": "Free test only (plan \"free\").",
1207
+ "type": "object",
1208
+ "properties": {
1209
+ "eligible": {
1210
+ "type": "boolean",
1211
+ "description": "false: this sign-up was refused free credits; choose a paid plan to continue."
1212
+ },
1213
+ "week": {
1214
+ "anyOf": [
1215
+ {
1216
+ "type": "integer",
1217
+ "minimum": -9007199254740991,
1218
+ "maximum": 9007199254740991
1219
+ },
1220
+ {
1221
+ "type": "null"
1222
+ }
1223
+ ],
1224
+ "description": "Current free week, 1–4; null after the end or when not eligible."
1225
+ },
1226
+ "weeks": {
1227
+ "type": "integer",
1228
+ "minimum": -9007199254740991,
1229
+ "maximum": 9007199254740991,
1230
+ "description": "Length of the free test in weeks (4)."
1231
+ },
1232
+ "creditsPerWeek": {
1233
+ "type": "integer",
1234
+ "minimum": -9007199254740991,
1235
+ "maximum": 9007199254740991,
1236
+ "description": "This week's grant: 100 in week 1, then 50. Credits left = credits.plan."
1237
+ },
1238
+ "nextResetAt": {
1239
+ "description": "Next weekly grant, Monday 00:00 UTC; null in the last week, after the end or when not eligible.",
1240
+ "type": [
1241
+ "string",
1242
+ "null"
1243
+ ]
1244
+ },
1245
+ "endsAt": {
1246
+ "description": "End of the free test (after the 4th week).",
1247
+ "type": [
1248
+ "string",
1249
+ "null"
1250
+ ]
1251
+ },
1252
+ "ended": {
1253
+ "type": "boolean"
1254
+ }
1255
+ },
1256
+ "required": [
1257
+ "eligible",
1258
+ "week",
1259
+ "weeks",
1260
+ "creditsPerWeek",
1261
+ "nextResetAt",
1262
+ "endsAt",
1263
+ "ended"
1264
+ ]
1265
+ }
1266
+ },
1267
+ "required": [
1268
+ "plan",
1269
+ "status",
1270
+ "credits",
1271
+ "rateLimit",
1272
+ "periodEndsAt"
1273
+ ]
1274
+ }
1275
+ }
1276
+ }
1277
+ }