@hashteelab/dodo-scan
v0.2.0
Published
SDK for Dodo document-capture scanners: cloud records, LAN scanning, delivery connectors, webhook verification
Maintainers
Readme
dodo-scan
TypeScript/Node SDK for Dodo — the network document-capture scanner: structured data out of paper, extracted by a cloud VLM against your own field schemas.
Zero dependencies. Node 18+.
npm install @hashteelab/dodo-scanPull records from Dodo Cloud
import { DodoCloud } from "@hashteelab/dodo-scan";
const cloud = new DodoCloud("api.getdodo.in", process.env.DODO_API_KEY!);
const records = await cloud.listExtractions({ status: "completed", q: "acme" });
for (const r of records) {
console.log(r.document_type, r.data);
}
// Fix a misread value and approve a needs_review record:
await cloud.reviewExtraction("ext_…", "completed", { total: 8050 });
// Everything the current filters match, as CSV:
const csv = await cloud.exportCsv({ profileId: "pr_…" });Trigger a scan on the scanner next to you (LAN)
import { DodoScanner } from "@hashteelab/dodo-scan";
const scanner = new DodoScanner("scanner.local:8443");
const record = await scanner.scan({
documentType: "purchase_invoice",
fields: {
supplier: "string",
total: "number",
line_items: [{ product: "string", qty: "number" }],
},
}); // resolves when the page is captured and extracted
console.log(record.data.total);Receive records by webhook
Create a webhook connector (store config.secret — it is shown once), then
verify every delivery:
const cn = await cloud.createConnector({
type: "webhook",
name: "My app",
config: { url: "https://example.com/dodo" },
});
// cn.config.secret is the whsec_… signing key — shown ONCERecords are fetched fresh at delivery time, so a review decision made before
delivery ships in its final form. Other connector types ("s3", and
"gsheets" — one spreadsheet row per record) use the same
createConnector / testConnector / listConnectorDeliveries surface.
import { verifyWebhookSignature } from "@hashteelab/dodo-scan";
app.post("/dodo", (req, res) => {
const ok = verifyWebhookSignature(
process.env.DODO_WEBHOOK_SECRET!,
req.rawBody, // the exact bytes, not re-serialized JSON
req.header("X-Dodo-Signature")!,
);
if (!ok) return res.status(401).end();
const { record } = JSON.parse(req.rawBody);
// … 2xx acknowledges; anything else is retried with backoff
res.status(200).end();
});© Hashtee Lab · MIT
