minifetch-api 1.5.0 → 1.6.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/README.md CHANGED
@@ -24,7 +24,7 @@
24
24
  - ***Or*** an Ethereum or Solana private key for making USDC payments on Base or Solana networks.
25
25
 
26
26
  **Payments.** Two ways to pay:
27
- 1. Credit card + API key. Get started free - [visit our dashboard to Sign Up](https://minifetch.com/dashboard). Create a Minifetch account and it will be auto-loaded with 25 free technical SEO page audits. Top up with your credit card later.
27
+ 1. Credit card + API key. Get started free - [visit our dashboard to Sign Up](https://minifetch.com/dashboard). Create a Minifetch account and it will be auto-loaded with credits worth up to 25 free technical SEO page audits. Top up with your credit card later.
28
28
  2. USDC on Base or Solana. Just load your wallet with USDC, you're ready. No "gas token" (ETH or SOL) required. You don't need a Minifetch account either, just load your wallet and go!
29
29
 
30
30
  ## Install
@@ -74,6 +74,8 @@ After the Quick Start, you have the following methods to use.
74
74
 
75
75
  The `checkAndExtract` methods check the target URL's `robots.txt` file to ensure its not blocked and tell us your preferred crawl delay (defaults to 1 second between requests to your domain). So fetching 10 URLs takes at least 10 seconds to complete by default. This is by design, so Minifetch never hammers your server or slows it down for your real users. If you own the site and want to allow Minifetch access or to set custom rules for it, read [How To Unblock Minifetch](https://minifetch.com/tutorials/unblock-minifetch).
76
76
 
77
+ All API methods default to POST unless you set options to `{ method: 'GET' }` and pass in as the second argument.
78
+
77
79
  ```js
78
80
  await client.checkAndRunSeoPageAudit(url);
79
81
  // Price: $0.01
@@ -152,18 +154,15 @@ When you wrap the functions above in a try/catch, here are some of the errors yo
152
154
 
153
155
  ---
154
156
 
155
- ### Service Limitations
156
- Minifetch only extracts publicly available metadata and content from pages accessible without authentication and javascript execution.
157
+ ### How We Fetch Web Pages
158
+ Minifetch extracts publicly available metadata and content from pages accessible without authentication or javascript execution.
157
159
 
158
- What Minifetch does *NOT* do:
159
- - Ignore robots.txt directives
160
- - Create accounts or log into user sessions
161
- - Perform transactional actions (checkout, bidding, purchasing, form submissions)
162
- - Bypass paywalls or access restricted content
160
+ Every response carries a `proxy` block: the `minifetch` user agent we sent and whether robots.txt was obeyed on the fetch. Proof of how the fetch happened, not just a promise, for regulated use-cases where provenance matters.
163
161
 
164
- What Minifetch does NOT do *currently* but may offer in the future as an add-on:
162
+ Future add-ons:
163
+ - Residential proxies for hard-to-reach pages
165
164
  - Javascript execution
166
- - Access authenticated or logged-in content
165
+ - Access to authenticated or logged-in content
167
166
 
168
167
  ---
169
168
 
@@ -1,12 +1,18 @@
1
1
  import { initConfig } from "./init.js";
2
2
  import { validateAndNormalizeUrl } from "./utils/validation.js";
3
3
  import { handlePayment, handleApiKeyRequest } from "./utils/payment.js";
4
- import { InvalidUrlError, RobotsBlockedError, PaymentFailedError, ExtractionFailedError, NetworkError, } from "./types/errors.js";
4
+ import { InvalidUrlError, RobotsBlockedError, PaymentFailedError, ExtractionFailedError, NetworkError, ConfigurationError, } from "./types/errors.js";
5
+ /** Every endpoint accepts GET (query string) or POST (JSON body). POST is the default. */
6
+ const DEFAULT_METHOD = "POST";
5
7
  /**
6
8
  * Main Minifetch API client.
7
9
  * Supports two auth modes:
8
10
  * - x402: crypto micropayments via Coinbase x402 (pass network + privateKey)
9
11
  * - apiKey: Stripe-backed credits (pass apiKey: "mf_prod_..." or "mf_dev_...")
12
+ *
13
+ * Every request method accepts an optional `method: "GET" | "POST"` in its
14
+ * options; it defaults to POST (params sent as a JSON body). Pass `method: "GET"`
15
+ * to send params in the query string instead.
10
16
  */
11
17
  export class MinifetchClient {
12
18
  config;
@@ -24,17 +30,18 @@ export class MinifetchClient {
24
30
  * @param url
25
31
  * @param options
26
32
  * @param options.fresh
33
+ * @param options.method - "GET" or "POST" (default POST)
27
34
  * @throws {InvalidUrlError} if URL is invalid
28
35
  * @throws {NetworkError} if request fails
29
36
  */
30
37
  async preflightUrlCheck(url, options) {
31
38
  try {
32
39
  const normalizedUrl = validateAndNormalizeUrl(url);
33
- const params = new URLSearchParams({ url: normalizedUrl });
40
+ const params = { url: normalizedUrl };
34
41
  if (options?.fresh)
35
- params.set("fresh", "true");
36
- const requestUrl = `${this.baseUrl}/api/v1/free/preflight/url-check?${params.toString()}`;
37
- const response = await fetch(requestUrl);
42
+ params.fresh = true;
43
+ const { url: requestUrl, init } = this._buildRequest("/api/v1/free/preflight/url-check", params, options?.method ?? DEFAULT_METHOD);
44
+ const response = await fetch(requestUrl, init);
38
45
  if (!response.ok) {
39
46
  throw new NetworkError(`Preflight check failed: ${response.status} ${response.statusText}`);
40
47
  }
@@ -47,21 +54,53 @@ export class MinifetchClient {
47
54
  throw new NetworkError(`Preflight check failed: ${error instanceof Error ? error.message : "Unknown error"}`);
48
55
  }
49
56
  }
57
+ /**
58
+ * INTERNAL / UNDOCUMENTED — deliberately omitted from the README and not part
59
+ * of the public API. The public {@link preflightUrlCheck} hits the FREE
60
+ * endpoint (no payment); this hits the PAID x402 twin at
61
+ * `/api/v1/x402/preflight/url-check` so our own suite can generate paid
62
+ * traffic against it — the x402 Bazaar weights usage for ranking and this
63
+ * refreshes the listing. x402 auth only; there is no session/api-key route
64
+ * for a paid url-check.
65
+ *
66
+ * @param url
67
+ * @param options
68
+ * @param options.fresh - bypass the 24h robots.txt cache
69
+ * @param options.method - "GET" or "POST" (default POST)
70
+ * @throws {ConfigurationError} if the client is not in x402 mode
71
+ * @internal
72
+ */
73
+ async _exercisePaidUrlCheck(url, options) {
74
+ if (this.config.authMode !== "x402") {
75
+ throw new ConfigurationError("_exercisePaidUrlCheck requires x402 auth (network + privateKey)");
76
+ }
77
+ try {
78
+ const normalizedUrl = validateAndNormalizeUrl(url);
79
+ const params = { url: normalizedUrl };
80
+ if (options?.fresh)
81
+ params.fresh = true;
82
+ return await this._makeRequest("/preflight/url-check", normalizedUrl, "Paid URL check", params, options?.method);
83
+ }
84
+ catch (error) {
85
+ return this._rethrowError(error, url, "Paid URL check");
86
+ }
87
+ }
50
88
  /**
51
89
  * Run SEO page audit (paid endpoint)
52
90
  *
53
91
  * @param url
92
+ * @param options
93
+ * @param options.method - "GET" or "POST" (default POST)
54
94
  * @throws {InvalidUrlError} if URL is invalid
55
95
  * @throws {ExtractionFailedError} various reasons, check README
56
96
  * @throws {PaymentFailedError} if x402 payment fails
57
97
  * @throws {NetworkError} various reasons, check README
58
98
  */
59
- async runSeoPageAudit(url) {
99
+ async runSeoPageAudit(url, options) {
60
100
  try {
61
101
  const normalizedUrl = validateAndNormalizeUrl(url);
62
- const params = new URLSearchParams({ url: normalizedUrl });
63
- const requestUrl = `${this.baseUrl}${this._paidPath("/run/seo-page-audit")}?${params.toString()}`;
64
- return await this._makeRequest(requestUrl, normalizedUrl, "Run SEO page audit");
102
+ const params = { url: normalizedUrl };
103
+ return await this._makeRequest("/run/seo-page-audit", normalizedUrl, "Run SEO page audit", params, options?.method);
65
104
  }
66
105
  catch (error) {
67
106
  return this._rethrowError(error, url, "Run SEO page audit");
@@ -75,6 +114,7 @@ export class MinifetchClient {
75
114
  * @param options.fields
76
115
  * @param options.omitEmpty
77
116
  * @param options.includeResponseBody
117
+ * @param options.method - "GET" or "POST" (default POST)
78
118
  * @throws {InvalidUrlError} if URL is invalid
79
119
  * @throws {ExtractionFailedError} various reasons, check README
80
120
  * @throws {PaymentFailedError} if x402 payment fails
@@ -83,15 +123,14 @@ export class MinifetchClient {
83
123
  async extractUrlMetadata(url, options) {
84
124
  try {
85
125
  const normalizedUrl = validateAndNormalizeUrl(url);
86
- const params = new URLSearchParams({ url: normalizedUrl });
126
+ const params = { url: normalizedUrl };
87
127
  if (options?.fields?.length)
88
- params.set("fields", options.fields.join(","));
128
+ params.fields = options.fields.join(",");
89
129
  if (options?.omitEmpty)
90
- params.set("omitEmpty", "true");
130
+ params.omitEmpty = true;
91
131
  if (options?.includeResponseBody)
92
- params.set("includeResponseBody", "true");
93
- const requestUrl = `${this.baseUrl}${this._paidPath("/extract/url-metadata")}?${params.toString()}`;
94
- return await this._makeRequest(requestUrl, normalizedUrl, "Metadata extraction");
132
+ params.includeResponseBody = true;
133
+ return await this._makeRequest("/extract/url-metadata", normalizedUrl, "Metadata extraction", params, options?.method);
95
134
  }
96
135
  catch (error) {
97
136
  return this._rethrowError(error, url, "Metadata extraction");
@@ -101,16 +140,18 @@ export class MinifetchClient {
101
140
  * Extract URL links (paid endpoint)
102
141
  *
103
142
  * @param url
143
+ * @param options
144
+ * @param options.method - "GET" or "POST" (default POST)
104
145
  * @throws {InvalidUrlError} if URL is invalid
105
146
  * @throws {ExtractionFailedError} various reasons, check README
106
147
  * @throws {PaymentFailedError} if x402 payment fails
107
148
  * @throws {NetworkError} various reasons, check README
108
149
  */
109
- async extractUrlLinks(url) {
150
+ async extractUrlLinks(url, options) {
110
151
  try {
111
152
  const normalizedUrl = validateAndNormalizeUrl(url);
112
- const requestUrl = `${this.baseUrl}${this._paidPath("/extract/url-links")}?url=${encodeURIComponent(normalizedUrl)}`;
113
- return await this._makeRequest(requestUrl, normalizedUrl, "Links extraction");
153
+ const params = { url: normalizedUrl };
154
+ return await this._makeRequest("/extract/url-links", normalizedUrl, "Links extraction", params, options?.method);
114
155
  }
115
156
  catch (error) {
116
157
  return this._rethrowError(error, url, "Links extraction");
@@ -120,16 +161,18 @@ export class MinifetchClient {
120
161
  * Extract URL preview (paid endpoint)
121
162
  *
122
163
  * @param url
164
+ * @param options
165
+ * @param options.method - "GET" or "POST" (default POST)
123
166
  * @throws {InvalidUrlError} if URL is invalid
124
167
  * @throws {ExtractionFailedError} various reasons, check README
125
168
  * @throws {PaymentFailedError} if x402 payment fails
126
169
  * @throws {NetworkError} various reasons, check README
127
170
  */
128
- async extractUrlPreview(url) {
171
+ async extractUrlPreview(url, options) {
129
172
  try {
130
173
  const normalizedUrl = validateAndNormalizeUrl(url);
131
- const requestUrl = `${this.baseUrl}${this._paidPath("/extract/url-preview")}?url=${encodeURIComponent(normalizedUrl)}`;
132
- return await this._makeRequest(requestUrl, normalizedUrl, "Preview extraction");
174
+ const params = { url: normalizedUrl };
175
+ return await this._makeRequest("/extract/url-preview", normalizedUrl, "Preview extraction", params, options?.method);
133
176
  }
134
177
  catch (error) {
135
178
  return this._rethrowError(error, url, "Preview extraction");
@@ -141,6 +184,7 @@ export class MinifetchClient {
141
184
  * @param url
142
185
  * @param options
143
186
  * @param options.includeMediaUrls
187
+ * @param options.method - "GET" or "POST" (default POST)
144
188
  * @throws {InvalidUrlError} if URL is invalid
145
189
  * @throws {ExtractionFailedError} various reasons, check README
146
190
  * @throws {PaymentFailedError} if x402 payment fails
@@ -149,11 +193,10 @@ export class MinifetchClient {
149
193
  async extractUrlContent(url, options) {
150
194
  try {
151
195
  const normalizedUrl = validateAndNormalizeUrl(url);
152
- const params = new URLSearchParams({ url: normalizedUrl });
196
+ const params = { url: normalizedUrl };
153
197
  if (options?.includeMediaUrls)
154
- params.set("includeMediaUrls", "true");
155
- const requestUrl = `${this.baseUrl}${this._paidPath("/extract/url-content")}?${params.toString()}`;
156
- return await this._makeRequest(requestUrl, normalizedUrl, "Content extraction");
198
+ params.includeMediaUrls = true;
199
+ return await this._makeRequest("/extract/url-content", normalizedUrl, "Content extraction", params, options?.method);
157
200
  }
158
201
  catch (error) {
159
202
  return this._rethrowError(error, url, "Content extraction");
@@ -164,10 +207,12 @@ export class MinifetchClient {
164
207
  * Throws RobotsBlockedError if robots.txt blocks the URL.
165
208
  *
166
209
  * @param url
210
+ * @param options
211
+ * @param options.method - "GET" or "POST" (default POST)
167
212
  */
168
- async checkAndRunSeoPageAudit(url) {
213
+ async checkAndRunSeoPageAudit(url, options) {
169
214
  await this._preflightOrThrow(url);
170
- return this.runSeoPageAudit(url);
215
+ return this.runSeoPageAudit(url, options);
171
216
  }
172
217
  /**
173
218
  * Check URL then extract metadata in one call.
@@ -178,6 +223,7 @@ export class MinifetchClient {
178
223
  * @param options.fields
179
224
  * @param options.omitEmpty
180
225
  * @param options.includeResponseBody
226
+ * @param options.method - "GET" or "POST" (default POST)
181
227
  */
182
228
  async checkAndExtractUrlMetadata(url, options) {
183
229
  await this._preflightOrThrow(url);
@@ -188,20 +234,24 @@ export class MinifetchClient {
188
234
  * Throws RobotsBlockedError if robots.txt blocks the URL.
189
235
  *
190
236
  * @param url
237
+ * @param options
238
+ * @param options.method - "GET" or "POST" (default POST)
191
239
  */
192
- async checkAndExtractUrlLinks(url) {
240
+ async checkAndExtractUrlLinks(url, options) {
193
241
  await this._preflightOrThrow(url);
194
- return this.extractUrlLinks(url);
242
+ return this.extractUrlLinks(url, options);
195
243
  }
196
244
  /**
197
245
  * Check URL then extract preview in one call.
198
246
  * Throws RobotsBlockedError if robots.txt blocks the URL.
199
247
  *
200
248
  * @param url
249
+ * @param options
250
+ * @param options.method - "GET" or "POST" (default POST)
201
251
  */
202
- async checkAndExtractUrlPreview(url) {
252
+ async checkAndExtractUrlPreview(url, options) {
203
253
  await this._preflightOrThrow(url);
204
- return this.extractUrlPreview(url);
254
+ return this.extractUrlPreview(url, options);
205
255
  }
206
256
  /**
207
257
  * Check URL then extract content in one call.
@@ -210,6 +260,7 @@ export class MinifetchClient {
210
260
  * @param url
211
261
  * @param options
212
262
  * @param options.includeMediaUrls
263
+ * @param options.method - "GET" or "POST" (default POST)
213
264
  */
214
265
  async checkAndExtractUrlContent(url, options) {
215
266
  await this._preflightOrThrow(url);
@@ -229,17 +280,46 @@ export class MinifetchClient {
229
280
  return this.config.authMode === "x402" ? `/api/v1/x402${endpoint}` : `/api/v1${endpoint}`;
230
281
  }
231
282
  /**
232
- * Dispatch to the correct request handler based on auth mode, then
233
- * normalize the response into PaidEndpointResponse.
283
+ * Encode a request for the wire. GET → params in the query string, no body.
284
+ * POST → params as a JSON body with a Content-Type header. Auth headers
285
+ * (Bearer / x402 payment) are added downstream, not here.
286
+ *
287
+ * @param path - absolute API path (already includes /api/v1[/x402])
288
+ * @param params - request params (string or boolean values)
289
+ * @param method - "GET" or "POST"
290
+ * @returns the full request URL and the fetch init (method + optional body/headers)
291
+ */
292
+ _buildRequest(path, params, method) {
293
+ if (method === "GET") {
294
+ const qs = new URLSearchParams();
295
+ for (const [key, value] of Object.entries(params))
296
+ qs.set(key, String(value));
297
+ return { url: `${this.baseUrl}${path}?${qs.toString()}`, init: { method: "GET" } };
298
+ }
299
+ return {
300
+ url: `${this.baseUrl}${path}`,
301
+ init: {
302
+ method: "POST",
303
+ headers: { "Content-Type": "application/json" },
304
+ body: JSON.stringify(params),
305
+ },
306
+ };
307
+ }
308
+ /**
309
+ * Build the request, dispatch to the correct auth handler, then normalize the
310
+ * response into PaidEndpointResponse.
234
311
  * Note: payment field is only present for x402 responses.
235
312
  *
236
- * @param requestUrl
313
+ * @param endpoint - endpoint path segment, e.g. "/extract/url-metadata"
237
314
  * @param normalizedUrl
238
315
  * @param label - used in error messages
316
+ * @param params - request params (string or boolean values)
317
+ * @param method - "GET" or "POST" (default POST)
239
318
  */
240
- async _makeRequest(requestUrl, normalizedUrl, label) {
319
+ async _makeRequest(endpoint, normalizedUrl, label, params, method = DEFAULT_METHOD) {
320
+ const { url, init } = this._buildRequest(this._paidPath(endpoint), params, method);
241
321
  if (this.config.authMode === "x402") {
242
- const { response, payment } = await handlePayment(requestUrl, this.config);
322
+ const { response, payment } = await handlePayment(url, this.config, init);
243
323
  if (!response.ok) {
244
324
  throw new ExtractionFailedError(normalizedUrl, `${label} failed: ${response.status} ${response.statusText}`);
245
325
  }
@@ -247,7 +327,7 @@ export class MinifetchClient {
247
327
  return { success: data.success, results: data.results, payment };
248
328
  }
249
329
  else {
250
- const { response } = await handleApiKeyRequest(requestUrl, this.config);
330
+ const { response } = await handleApiKeyRequest(url, this.config, init);
251
331
  if (!response.ok) {
252
332
  throw new ExtractionFailedError(normalizedUrl, `${label} failed: ${response.status} ${response.statusText}`);
253
333
  }
@@ -15,7 +15,7 @@ import { PaymentFailedError, NetworkError } from "../types/errors.js";
15
15
  * @param url
16
16
  * @param config
17
17
  */
18
- export async function handlePayment(url, config) {
18
+ export async function handlePayment(url, config, init) {
19
19
  try {
20
20
  const _x402Client = new x402Client();
21
21
  let payer;
@@ -40,7 +40,8 @@ export async function handlePayment(url, config) {
40
40
  throw new PaymentFailedError(`Unsupported network: ${config.network}`);
41
41
  }
42
42
  const fetchWithPayment = wrapFetchWithPayment(fetch, _x402Client);
43
- const response = await fetchWithPayment(url, { method: "GET" });
43
+ // Default GET when no init passed; init carries method + JSON body for POST.
44
+ const response = await fetchWithPayment(url, init ?? { method: "GET" });
44
45
  if (!response.ok) {
45
46
  const serverMessage = await readServerErrorMessage(response);
46
47
  throw new NetworkError(`Request failed: ${response.status} ${response.statusText}${serverMessage ? ` — ${serverMessage}` : ""}`);
@@ -72,10 +73,12 @@ export async function handlePayment(url, config) {
72
73
  * @param url
73
74
  * @param config
74
75
  */
75
- export async function handleApiKeyRequest(url, config) {
76
+ export async function handleApiKeyRequest(url, config, init) {
76
77
  const response = await fetch(url, {
77
- method: "GET",
78
+ ...init,
79
+ method: init?.method ?? "GET",
78
80
  headers: {
81
+ ...init?.headers,
79
82
  Authorization: `Bearer ${config.apiKey}`,
80
83
  },
81
84
  });
@@ -1,10 +1,14 @@
1
- import type { ClientConfig } from "./types/config.js";
1
+ import type { ClientConfig, HttpMethod } from "./types/config.js";
2
2
  import type { PreflightCheckResponse, PaidEndpointResponse } from "./types/responses.js";
3
3
  /**
4
4
  * Main Minifetch API client.
5
5
  * Supports two auth modes:
6
6
  * - x402: crypto micropayments via Coinbase x402 (pass network + privateKey)
7
7
  * - apiKey: Stripe-backed credits (pass apiKey: "mf_prod_..." or "mf_dev_...")
8
+ *
9
+ * Every request method accepts an optional `method: "GET" | "POST"` in its
10
+ * options; it defaults to POST (params sent as a JSON body). Pass `method: "GET"`
11
+ * to send params in the query string instead.
8
12
  */
9
13
  export declare class MinifetchClient {
10
14
  private config;
@@ -19,22 +23,48 @@ export declare class MinifetchClient {
19
23
  * @param url
20
24
  * @param options
21
25
  * @param options.fresh
26
+ * @param options.method - "GET" or "POST" (default POST)
22
27
  * @throws {InvalidUrlError} if URL is invalid
23
28
  * @throws {NetworkError} if request fails
24
29
  */
25
30
  preflightUrlCheck(url: string, options?: {
26
31
  fresh?: boolean;
32
+ method?: HttpMethod;
27
33
  }): Promise<PreflightCheckResponse>;
34
+ /**
35
+ * INTERNAL / UNDOCUMENTED — deliberately omitted from the README and not part
36
+ * of the public API. The public {@link preflightUrlCheck} hits the FREE
37
+ * endpoint (no payment); this hits the PAID x402 twin at
38
+ * `/api/v1/x402/preflight/url-check` so our own suite can generate paid
39
+ * traffic against it — the x402 Bazaar weights usage for ranking and this
40
+ * refreshes the listing. x402 auth only; there is no session/api-key route
41
+ * for a paid url-check.
42
+ *
43
+ * @param url
44
+ * @param options
45
+ * @param options.fresh - bypass the 24h robots.txt cache
46
+ * @param options.method - "GET" or "POST" (default POST)
47
+ * @throws {ConfigurationError} if the client is not in x402 mode
48
+ * @internal
49
+ */
50
+ _exercisePaidUrlCheck(url: string, options?: {
51
+ fresh?: boolean;
52
+ method?: HttpMethod;
53
+ }): Promise<PaidEndpointResponse>;
28
54
  /**
29
55
  * Run SEO page audit (paid endpoint)
30
56
  *
31
57
  * @param url
58
+ * @param options
59
+ * @param options.method - "GET" or "POST" (default POST)
32
60
  * @throws {InvalidUrlError} if URL is invalid
33
61
  * @throws {ExtractionFailedError} various reasons, check README
34
62
  * @throws {PaymentFailedError} if x402 payment fails
35
63
  * @throws {NetworkError} various reasons, check README
36
64
  */
37
- runSeoPageAudit(url: string): Promise<PaidEndpointResponse>;
65
+ runSeoPageAudit(url: string, options?: {
66
+ method?: HttpMethod;
67
+ }): Promise<PaidEndpointResponse>;
38
68
  /**
39
69
  * Extract URL metadata (paid endpoint)
40
70
  *
@@ -43,6 +73,7 @@ export declare class MinifetchClient {
43
73
  * @param options.fields
44
74
  * @param options.omitEmpty
45
75
  * @param options.includeResponseBody
76
+ * @param options.method - "GET" or "POST" (default POST)
46
77
  * @throws {InvalidUrlError} if URL is invalid
47
78
  * @throws {ExtractionFailedError} various reasons, check README
48
79
  * @throws {PaymentFailedError} if x402 payment fails
@@ -52,33 +83,43 @@ export declare class MinifetchClient {
52
83
  fields?: string[];
53
84
  omitEmpty?: boolean;
54
85
  includeResponseBody?: boolean;
86
+ method?: HttpMethod;
55
87
  }): Promise<PaidEndpointResponse>;
56
88
  /**
57
89
  * Extract URL links (paid endpoint)
58
90
  *
59
91
  * @param url
92
+ * @param options
93
+ * @param options.method - "GET" or "POST" (default POST)
60
94
  * @throws {InvalidUrlError} if URL is invalid
61
95
  * @throws {ExtractionFailedError} various reasons, check README
62
96
  * @throws {PaymentFailedError} if x402 payment fails
63
97
  * @throws {NetworkError} various reasons, check README
64
98
  */
65
- extractUrlLinks(url: string): Promise<PaidEndpointResponse>;
99
+ extractUrlLinks(url: string, options?: {
100
+ method?: HttpMethod;
101
+ }): Promise<PaidEndpointResponse>;
66
102
  /**
67
103
  * Extract URL preview (paid endpoint)
68
104
  *
69
105
  * @param url
106
+ * @param options
107
+ * @param options.method - "GET" or "POST" (default POST)
70
108
  * @throws {InvalidUrlError} if URL is invalid
71
109
  * @throws {ExtractionFailedError} various reasons, check README
72
110
  * @throws {PaymentFailedError} if x402 payment fails
73
111
  * @throws {NetworkError} various reasons, check README
74
112
  */
75
- extractUrlPreview(url: string): Promise<PaidEndpointResponse>;
113
+ extractUrlPreview(url: string, options?: {
114
+ method?: HttpMethod;
115
+ }): Promise<PaidEndpointResponse>;
76
116
  /**
77
117
  * Extract URL content as markdown (paid endpoint)
78
118
  *
79
119
  * @param url
80
120
  * @param options
81
121
  * @param options.includeMediaUrls
122
+ * @param options.method - "GET" or "POST" (default POST)
82
123
  * @throws {InvalidUrlError} if URL is invalid
83
124
  * @throws {ExtractionFailedError} various reasons, check README
84
125
  * @throws {PaymentFailedError} if x402 payment fails
@@ -86,14 +127,19 @@ export declare class MinifetchClient {
86
127
  */
87
128
  extractUrlContent(url: string, options?: {
88
129
  includeMediaUrls?: boolean;
130
+ method?: HttpMethod;
89
131
  }): Promise<PaidEndpointResponse>;
90
132
  /**
91
133
  * Check URL then run SEO page audit in one call.
92
134
  * Throws RobotsBlockedError if robots.txt blocks the URL.
93
135
  *
94
136
  * @param url
137
+ * @param options
138
+ * @param options.method - "GET" or "POST" (default POST)
95
139
  */
96
- checkAndRunSeoPageAudit(url: string): Promise<PaidEndpointResponse>;
140
+ checkAndRunSeoPageAudit(url: string, options?: {
141
+ method?: HttpMethod;
142
+ }): Promise<PaidEndpointResponse>;
97
143
  /**
98
144
  * Check URL then extract metadata in one call.
99
145
  * Throws RobotsBlockedError if robots.txt blocks the URL.
@@ -103,26 +149,36 @@ export declare class MinifetchClient {
103
149
  * @param options.fields
104
150
  * @param options.omitEmpty
105
151
  * @param options.includeResponseBody
152
+ * @param options.method - "GET" or "POST" (default POST)
106
153
  */
107
154
  checkAndExtractUrlMetadata(url: string, options?: {
108
155
  fields?: string[];
109
156
  omitEmpty?: boolean;
110
157
  includeResponseBody?: boolean;
158
+ method?: HttpMethod;
111
159
  }): Promise<PaidEndpointResponse>;
112
160
  /**
113
161
  * Check URL then extract links in one call.
114
162
  * Throws RobotsBlockedError if robots.txt blocks the URL.
115
163
  *
116
164
  * @param url
165
+ * @param options
166
+ * @param options.method - "GET" or "POST" (default POST)
117
167
  */
118
- checkAndExtractUrlLinks(url: string): Promise<PaidEndpointResponse>;
168
+ checkAndExtractUrlLinks(url: string, options?: {
169
+ method?: HttpMethod;
170
+ }): Promise<PaidEndpointResponse>;
119
171
  /**
120
172
  * Check URL then extract preview in one call.
121
173
  * Throws RobotsBlockedError if robots.txt blocks the URL.
122
174
  *
123
175
  * @param url
176
+ * @param options
177
+ * @param options.method - "GET" or "POST" (default POST)
124
178
  */
125
- checkAndExtractUrlPreview(url: string): Promise<PaidEndpointResponse>;
179
+ checkAndExtractUrlPreview(url: string, options?: {
180
+ method?: HttpMethod;
181
+ }): Promise<PaidEndpointResponse>;
126
182
  /**
127
183
  * Check URL then extract content in one call.
128
184
  * Throws RobotsBlockedError if robots.txt blocks the URL.
@@ -130,9 +186,11 @@ export declare class MinifetchClient {
130
186
  * @param url
131
187
  * @param options
132
188
  * @param options.includeMediaUrls
189
+ * @param options.method - "GET" or "POST" (default POST)
133
190
  */
134
191
  checkAndExtractUrlContent(url: string, options?: {
135
192
  includeMediaUrls?: boolean;
193
+ method?: HttpMethod;
136
194
  }): Promise<PaidEndpointResponse>;
137
195
  /**
138
196
  * Returns the correct paid path segment based on auth mode.
@@ -143,13 +201,26 @@ export declare class MinifetchClient {
143
201
  */
144
202
  private _paidPath;
145
203
  /**
146
- * Dispatch to the correct request handler based on auth mode, then
147
- * normalize the response into PaidEndpointResponse.
204
+ * Encode a request for the wire. GET → params in the query string, no body.
205
+ * POST → params as a JSON body with a Content-Type header. Auth headers
206
+ * (Bearer / x402 payment) are added downstream, not here.
207
+ *
208
+ * @param path - absolute API path (already includes /api/v1[/x402])
209
+ * @param params - request params (string or boolean values)
210
+ * @param method - "GET" or "POST"
211
+ * @returns the full request URL and the fetch init (method + optional body/headers)
212
+ */
213
+ private _buildRequest;
214
+ /**
215
+ * Build the request, dispatch to the correct auth handler, then normalize the
216
+ * response into PaidEndpointResponse.
148
217
  * Note: payment field is only present for x402 responses.
149
218
  *
150
- * @param requestUrl
219
+ * @param endpoint - endpoint path segment, e.g. "/extract/url-metadata"
151
220
  * @param normalizedUrl
152
221
  * @param label - used in error messages
222
+ * @param params - request params (string or boolean values)
223
+ * @param method - "GET" or "POST" (default POST)
153
224
  */
154
225
  private _makeRequest;
155
226
  /**
@@ -1,5 +1,7 @@
1
1
  export declare const VALID_NETWORKS: readonly ["base", "base-sepolia", "solana", "solana-devnet"];
2
2
  export type Network = (typeof VALID_NETWORKS)[number];
3
+ /** HTTP method for a request. Every endpoint accepts GET (query string) or POST (JSON body). */
4
+ export type HttpMethod = "GET" | "POST";
3
5
  /**
4
6
  * Config for x402 crypto micropayment auth
5
7
  */
@@ -10,7 +10,7 @@ import type { PaymentInfo } from "../types/responses.js";
10
10
  * @param url
11
11
  * @param config
12
12
  */
13
- export declare function handlePayment(url: string, config: InitializedConfig): Promise<{
13
+ export declare function handlePayment(url: string, config: InitializedConfig, init?: RequestInit): Promise<{
14
14
  response: Response;
15
15
  payment?: PaymentInfo;
16
16
  }>;
@@ -21,6 +21,6 @@ export declare function handlePayment(url: string, config: InitializedConfig): P
21
21
  * @param url
22
22
  * @param config
23
23
  */
24
- export declare function handleApiKeyRequest(url: string, config: InitializedConfig): Promise<{
24
+ export declare function handleApiKeyRequest(url: string, config: InitializedConfig, init?: RequestInit): Promise<{
25
25
  response: Response;
26
26
  }>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "minifetch-api",
3
- "version": "1.5.0",
4
- "description": "Minifetch.com API Client. Pay-per-URL SEO audits. Composable toolkit for AI agents and automation pipelines.",
3
+ "version": "1.6.0",
4
+ "description": "Minifetch.com API Client. Scrape, extract and audit web pages. Pay per URL, no subscription.",
5
5
  "type": "module",
6
6
  "main": "./dist/esm/index.js",
7
7
  "types": "./dist/types/index.d.ts",
@@ -17,43 +17,43 @@
17
17
  "LICENSE"
18
18
  ],
19
19
  "keywords": [
20
+ "html",
21
+ "web page",
22
+ "scraper",
23
+ "parser",
24
+ "metadata",
25
+ "metadata extraction",
26
+ "content extraction",
27
+ "link extraction",
28
+ "hosted",
29
+ "meta tags",
30
+ "open graph",
31
+ "og tags",
32
+ "previews",
33
+ "social cards",
34
+ "twitter cards",
35
+ "pay-per-fetch",
36
+ "pay-per-url",
37
+ "indexing",
38
+ "extract",
39
+ "json-ld",
40
+ "JSON LD",
41
+ "link analysis",
20
42
  "SEO",
21
43
  "SEO page audit",
22
44
  "SEO research",
23
45
  "SEO toolkit",
24
46
  "SEO skill",
25
47
  "technical SEO",
26
- "pay-per-fetch",
27
- "pay-per-url",
28
48
  "GEO",
29
49
  "Generative Engine Optimization",
30
50
  "AEO",
31
51
  "Answer Engine Optimization",
32
- "hosted extraction",
33
- "content extraction",
34
- "content indexing",
35
- "extract",
36
- "html",
37
- "html parser",
38
- "json-ld",
39
- "JSON LD",
40
- "link analysis",
41
- "link extraction",
42
- "metadata",
43
- "meta tags",
44
- "open graph",
45
- "og tags",
46
52
  "AI",
47
53
  "AI Agents",
48
54
  "AI readability",
49
- "agent skills",
50
55
  "automation",
51
- "monitoring",
52
56
  "LLM",
53
- "previews",
54
- "social cards",
55
- "twitter cards",
56
- "site monitoring",
57
57
  "x402",
58
58
  "micropayments",
59
59
  "usdc"