Node.js
X1-BaaS is a plain REST API. This guide provides a zero-dependency client using the built-infetch (Node 18+), with optional axios examples.
Requirements
- Node.js 18+ (native
fetch)
Client wrapper
Filename baas.js
const BASE_URL = "https://api.tazpal.com";
class BaasClient {
constructor({ apiKey, paymentPermit, timeout = 120000 } = {}) {
this.apiKey = apiKey;
this.paymentPermit = paymentPermit; // base64-encoded x402 permit
this.timeout = timeout;
}
headers() {
const h = { "Content-Type": "application/json" };
if (this.apiKey) h.Authorization = `Bearer ${this.apiKey}`;
else if (this.paymentPermit) h["X-PAYMENT"] = this.paymentPermit;
return h;
}
async request(method, path, body) {
const resp = await fetch(`${BASE_URL}${path}`, {
method,
headers: this.headers(),
body: body ? JSON.stringify(body) : undefined,
signal: AbortSignal.timeout(this.timeout),
});
const json = await resp.json().catch(() => ({}));
if (!resp.ok) throw new BaasError(resp.status, json);
return json;
}
scrape(url, output = "markdown", options = {}) {
const body = { url, output };
if (Object.keys(options).length) body.options = options;
return this.request("POST", "/v1/scrape", body);
}
extract(url, { schema, selectors, xpaths } = {}) {
const body = { url };
if (schema) body.schema = schema;
if (selectors) body.selectors = selectors;
if (xpaths) body.xpaths = xpaths;
return this.request("POST", "/v1/extract", body);
}
crawl({ startUrl, mode, urls, ...rest } = {}) {
const body = { mode, ...rest };
if (startUrl) body.start_url = startUrl;
if (urls) body.urls = urls;
return this.request("POST", "/v1/crawl", body);
}
crawlStatus(jobId) {
return this.request("GET", `/v1/crawl/${jobId}`);
}
crawlResults(jobId, limit = 100) {
return this.request("GET", `/v1/crawl/${jobId}/results?limit=${limit}`);
}
async cancelCrawl(jobId) {
await fetch(`${BASE_URL}/v1/crawl/${jobId}`, {
method: "DELETE",
headers: this.headers(),
});
}
health() {
return this.request("GET", "/health");
}
pricing() {
return this.request("GET", "/v1/pricing");
}
}
class BaasError extends Error {
constructor(statusCode, body) {
super(`HTTP ${statusCode}: ${JSON.stringify(body)}`);
this.statusCode = statusCode;
this.body = body;
}
}
module.exports = { BaasClient, BaasError };
Usage
Scrape to Markdown
const { BaasClient, BaasError } = require("./baas");
const client = new BaasClient({ apiKey: "baas_live_YOUR_KEY" });
try {
const result = await client.scrape("https://news.ycombinator.com");
console.log(result.data.title);
console.log(result.data.markdown.slice(0, 500));
} catch (err) {
if (err instanceof BaasError) console.error(err.statusCode, err.body);
}
Screenshot to file
import { writeFileSync } from "fs";
const result = await client.scrape("https://example.com", "screenshot", {
full_page: true,
});
writeFileSync("page.png", Buffer.from(result.data.data, "base64"));
Structured extraction
const result = await client.extract("https://example.com/product/123", {
schema: {
type: "object",
properties: {
title: { type: "string" },
price: { type: "number" },
},
},
});
console.log(result.data, result.metadata.confidence);
Crawl a batch and poll
const job = await client.crawl({
mode: "batch",
urls: ["https://a.com/1", "https://a.com/2"],
options: { parallel: 10 },
});
let status;
do {
await new Promise((r) => setTimeout(r, 5000));
status = await client.crawlStatus(job.job_id);
console.log(status.progress);
} while (!["completed", "failed", "canceled"].includes(status.status));
const results = await client.crawlResults(job.job_id);
console.log(`Got ${results.count} pages`);
Using axios instead
Preferaxios? Swap the request method:
import axios from "axios";
async request(method, path, body) {
try {
const { data } = await axios({
method,
url: `${BASE_URL}${path}`,
headers: this.headers(),
data: body,
timeout: this.timeout,
});
return data;
} catch (err) {
if (err.response) throw new BaasError(err.response.status, err.response.data);
throw err;
}
}
Error handling
Checkerr.statusCode and err.body.detail.error for the machine-readable code.
try {
await client.scrape("https://example.com", "nope");
} catch (err) {
if (err instanceof BaasError) {
console.log(err.body.detail.error); // "invalid_output"
console.log(err.body.detail.message);
}
}