@patchr-core/sdk
v0.1.5
Published
Agentic workflow SDK — proof cards, contracts, human handoffs, MCP/A2A
Maintainers
Readme
Patchr Node.js SDK
Patchr - the infrastructure for autonomous agents that need contracts, evidence trails, and human-safe handoffs.
Agentic workflow infrastructure — contracts, proof cards, human handoffs, MCP/A2A surfaces.
Step 0: Get your API token
Sign up free at patchr.co/signup — OAuth with Google, GitHub, or Microsoft. No credit card required. Your API token is on the dashboard immediately after signup.
export PATCHR_API_TOKEN="your_token_here"
export PATCHR_API_BASE_URL="https://api.patchr.co" # default — can omitInstall
npm install @patchr-core/sdkRequires Node.js 18+.
Quick Start
import { PatchrClient } from "@patchr-core/sdk";
// Reads PATCHR_API_TOKEN from env — throws a clear error with a signup
// link if the variable is not set.
const patchr = PatchrClient.fromEnv();
const run = await patchr.runOrchestrator({
clientId: "claims_demo",
channel: "sdk",
conversationId: "conv_damage_claim_001",
request: "My TV was damaged in transit and merchant support has not followed up.",
attachments: [
{
name: "damaged-tv-photo.jpg",
mime: "image/jpeg",
text: "Cracked TV panel and damaged transport packaging.",
},
],
});
console.log(run.status); // "ready" | "NEEDS_INPUT" | "proxyEscalated"
console.log(run.proofCard); // { title, evidenceStatus, confidence, ... }No token yet?
PatchrClient.fromEnv()throws:Error: PATCHR_API_TOKEN is not set. Get a free API token at https://www.patchr.co/signup Then: export PATCHR_API_TOKEN=your_token
Sandbox first (no API token needed)
Before writing code, try the hosted sandbox to see what a real run looks like:
Pick a scenario, send a request, and watch the orchestrator coordinate Hunt, Resolve, Proxy, and Pay in real time — no signup required.
Fast Sandbox Smoke Test
For CI or local testing without hitting live marketplaces, supply a source URL so Hunt has a known result:
const smoke = await patchr.runOrchestrator({
clientId: "sandbox_smoke_test",
channel: "sdk",
conversationId: "conv_iphone7_smoke_001",
request: "Buy me iPhone7 less than 500 dollar",
urls: [
"data:text/html,<html><title>Used iPhone7 listing</title><body>Used iPhone7 listing available in stock. List 600 dollar, sale 189.99 dollar with receipt and fast shipping.</body></html>",
],
targetLimit: 1,
allowNetwork: false,
});
console.log(smoke.status); // "NEEDS_INPUT" — source-backed result ready to selectRemove urls and omit allowNetwork to enable live marketplace search.
Streaming progress
for await (const event of patchr.streamOrchestrator({
clientId: "local_services_demo",
channel: "sdk",
conversationId: "conv_lekki_mechanic_001",
request: "Find me a mechanic in Lekki, Lagos",
country: "NG",
stream: true,
})) {
if (event.type === "progress" || event.type === "handoff") {
console.log(event.message);
}
if (event.type === "final") {
console.log(event.result.status);
}
}Event types: progress (quiet-period heartbeat), handoff (agent starting human-facing work), terminal (trace line), final (complete result).
Resuming a paused run
When a run returns status: "NEEDS_INPUT" (result selection) or status: "proxyEscalated" (human handoff required), resume it after the human step completes:
// First run — paused for result selection
const run = await patchr.runOrchestrator({ ... });
// run.status === "NEEDS_INPUT"
// run.decisionTree.paths has the ranked options
// Resume after the user selects a result
const resumed = await patchr.resumeOrchestrator(
run.conversationId, // from the original run
run.results.hunt.selected.candidateId,
"select",
);Common scenarios
// Disputed claim
await patchr.runOrchestrator({
clientId: "support_ops_demo",
channel: "sdk",
conversationId: "conv_ticket_dispute_001",
request: "Dispute ticket ZD-44291: airline charged me twice and closed the refund case.",
});
// Vendor due diligence workflow template
await patchr.runWorkflowTemplate("vendorDueDiligence", {
request: "Run due diligence on Acme Supply Co. for Q3 onboarding",
metadata: {
vendorName: "Acme Supply Co.",
website: "https://acme.example",
jurisdiction: "US",
policyRules: ["priceVarianceUnder5pct", "noSanctionedEntities"],
},
});
// Job offer verification
await patchr.runWorkflowTemplate("fakeJobVerification", {
request: "Verify this recruiter claiming to be from a Fortune 500",
metadata: { recruiterName: "Jane Smith", companyName: "Acme Corp", fees: true },
});Developer Activation
If you need to create a Patchr account programmatically (CI pipelines, onboarding flows), use createProfile. For interactive use, sign up at patchr.co/signup instead — it's faster.
const patchr = new PatchrClient(); // no token yet
const profile = await patchr.createProfile("[email protected]", "Dev Example") as {
token: string;
activation?: { message?: string; activationToken?: string };
};
// Patchr sends an activation email. Click it to lift the 5-request limit.
// In local/debug mode, the response includes activationToken for automated tests:
const activationToken = profile.activation?.activationToken;
if (activationToken) {
await patchr.activateToken(activationToken);
}
const activatedPatchr = new PatchrClient({ token: profile.token });
const run = await activatedPatchr.runOrchestrator({
clientId: "activation_smoke_test",
channel: "sdk",
request: "Buy me iPhone7 less than 500 dollar",
});Activation limit: Unactivated starter tokens are limited to 5 workflow requests. After the 5th request you will receive a
429error. Click the activation link in your email, or visit patchr.co/dashboard to manage your token.
All methods
// Protocol discovery
await patchr.health();
await patchr.apiStatus();
await patchr.manifest();
await patchr.protocolMap();
await patchr.listSchemas();
await patchr.getSchema(schemaId);
// Workflow templates
await patchr.listWorkflowTemplates();
await patchr.getWorkflowTemplate(templateId);
await patchr.runWorkflowTemplate(templateId, payload);
// Orchestrator
await patchr.runOrchestrator(payload);
await patchr.resumeOrchestrator(conversationId, itemId, action, payload?);
for await (const event of patchr.streamOrchestrator(payload)) { ... }
// Tools
await patchr.mapTool(payload); // geocode / location enrichment
await patchr.nlpTool(payload); // classify / extract / rewrite
// A2A / Tasks / Proof
await patchr.createA2AEnvelope(payload);
await patchr.createTask(payload);
await patchr.createProofPack(payload);
// Developer activation
await patchr.createProfile(email, name);
await patchr.activateToken(activationToken);Default API base URL: https://api.patchr.co
Error handling
import { PatchrApiError } from "@patchr-core/sdk";
try {
const run = await patchr.runOrchestrator({ request: "..." });
} catch (err) {
if (err instanceof PatchrApiError) {
console.error(err.status); // 401, 429, 500, etc.
console.error(err.message); // includes signup/upgrade link for 401/403
console.error(err.payload); // raw API error response
}
}Error messages for 401 and 403 include a direct link to patchr.co/signup so the path forward is always clear.
Links
- Signup — patchr.co/signup
- Dashboard — patchr.co/dashboard
- API reference — patchr.co/api
- Sandbox — patchr.co/sandbox
- Changelog — CHANGELOG.md
- Issues — github.com/orepos/Patchr/issues
Changelog
0.1.5 — removes password from createProfile (email + name only, consistent with OAuth web signup); adds resumeOrchestrator, mapTool, nlpTool implementations; fromEnv() throws a clear error with signup URL when PATCHR_API_TOKEN is not set; 401/403 errors include a signup link; removes internal PICUX_API_TOKEN fallback; expands npm keywords; fixes homepage URL.
0.1.4 — adds createProfile and activateToken for SDK-first developer activation; 5-request unactivated token limit.
0.1.3 — deterministic Hunt smoke test with supplied source URL.
See CHANGELOG.md for full release notes.
