Canonical submission and original-command recovery
Use POST /v1/quotes, then POST /v1/tasks with productId, the approved input, the quoted expectedPricingVersion, and the canonical Idempotency-Key. The host creates a key once for explicitly approved new work, using new_command_key() from the bundled REST engine, and persists it with the approved input before submission. Keys have the form v1.<13-digit Unix milliseconds>.<22–64 base64url characters>. Do not generate keys in model arguments or a workflow retry expression.
Creation requires allow_write=True, the persisted request_key, and explicit command_mode="new". The default command_mode="recover" performs an original-command GET and never obtains another quote or submits again. Repeated invocation in the same new-intent toolset also reads the original after its first submission attempt. Changed input is refused. After a restart or any lost response, use this host-only path; it needs no input, quote or model call:
import os
from truefetch_rest import recover_command, observed_task_id
original = recover_command(
os.environ["TRUEFETCH_API_KEY"], "tasks.create", os.environ["TRUEFETCH_COMMAND_KEY"]
)
if original["receipt"]["outcome"] == "accepted":
saved_task_id = observed_task_id(original)
# Persist the reference before reading the existing task/results.
HTTP 200 is not acceptance. Inspect receipt.outcome: accepted supplies an authoritative task reference even when the current task projection is null; processing and unknown require another explicit original GET, respecting the returned retry interval. rejected and not_accepted_final establish nonacceptance and require deliberate new work if you still want a collection. receipt_expired remains unconfirmed: inspect Tasks or contact support. The helper never seals, replays a POST or creates a replacement key. The server accepts new keys for 24 hours, allows five minutes of future clock skew, and retains terminal receipts for at least seven days; it can still answer a retained original after the new-command window ends. A current Task state does not establish a particular command’s outcome.
Cancellation is a separate command: bind a different persisted canonical cancel_key for the newly created task, or pass cancel_task_ids=(saved_task_id,) and cancel_command_keys={saved_task_id: saved_cancel_key} for an explicitly approved saved target. POST /v1/tasks/{taskId}/cancel sends {} and that cancellation key. Unknown cancellation is recovered with recover_command(api_key, "tasks.cancel", saved_cancel_key), never the creation key. Acceptance of cancellation does not promise the task ended as cancelled. The budget, keys and cancellation mapping remain host-only arguments.
Download the Python example
Save these files in the same directory:
Preview: tested with Python 3.12 and langchain-core==1.6.5, using real LangChain tools and a simulated HTTP API. Real-model tool selection, live credentials and upstream collection are not yet verified. This example uses REST; it does not require MCP to be open and is not an official LangChain registry integration.
Install the requirements in your Python virtual environment:
python -m pip install -r requirements.txt
Store your TrueFetch API key in TRUEFETCH_API_KEY. Keep it outside prompts, source code and tool arguments. If you use a model, install and configure your chosen LangChain provider separately; its model calls may have separate fees.
Set the budget in your application
The application supplies the key, credit limit and one stable request key. They are not exposed as arguments the model can change.
import os
from truefetch_tools import make_tools, recover_results
tools = make_tools(
os.environ["TRUEFETCH_API_KEY"],
max_credits=100,
request_key=os.environ["TRUEFETCH_COMMAND_KEY"],
command_mode="new",
allow_write=True,
)
by_name = {tool.name: tool for tool in tools}
job_input = {
"keyword": "Software engineer",
"country": "Germany",
"platforms": ["arbeitnow"],
"maxResults": 10,
}
estimate = by_name["truefetch_estimate"].invoke({"input": job_input})
accepted = by_name["truefetch_search_jobs"].invoke({"input": job_input})
if accepted["receipt"]["outcome"] != "accepted":
raise RuntimeError("Command is not accepted; inspect its original receipt before new work")
task_id = next(
ref["id"] for ref in accepted["receipt"]["result"]["objects"] if ref["kind"] == "task"
) # Persist before further processing.
result = recover_results(tools, task_id)
Estimation is read-only. Creation checks a fresh quote and passes the pricing version and budget to the API; it reserves credits and can incur collection charges. The configured limit is a per-collection maximum, not a monthly cap. Set API-key spending limits in your workspace separately. One credit equals 1,000,000 billing units; the current estimate determines the reservation.
Persist the request key and original input before submission. Repeated invocation after the first submission attempt reads that original command receipt. Changing input while reusing the key is a conflict; changing the key creates a new collection intent. The adapter never generates a replacement key or automatically retries a failed HTTP request.
Choose the tools your session needs
| Tool | Behavior |
|---|---|
truefetch_get_usage |
Read account credits and limits. |
truefetch_estimate |
Estimate collection against the application’s fixed budget. |
truefetch_get_task |
Read task metadata and one available result page. |
truefetch_list_tasks |
Read one page of account tasks. |
truefetch_search_jobs |
Create or recover the single configured collection intent. Requires write mode. |
truefetch_cancel_task |
Cancel a task created in this session or explicitly scoped by the application. Requires write mode; committed completion remains final. |
make_tools defaults to the four read/estimate tools. Write mode also requires a write-capable API key. For an agent session, pass these tools to your model’s bind_tools, or use the supplied run_agent(model, prompt, ...) helper. It bounds tool calls and steps, returns tool errors to the model, and defaults to read-only access. Supply your configured model; the example does not create one or choose a provider.
Reading or listing a task does not enable cancellation. For an explicitly intended cancellation after restart, the application can pass cancel_task_ids=(saved_task_id,). This scope stays outside the model’s arguments; server-side ownership and credential checks still apply.
Recover and verify saved results
On restart, use the saved task ID with recover_results. This path polls and reads; it never creates another collection. Pending work is not failure. If a local polling limit is reached, keep the ID and resume later. If submission timed out before you received the ID, preserve the original request key and input and recover the accepted intent before starting a new one.
truefetch_get_task returns one page, not a complete export. recover_results follows all cursors, checks record order and the committed count, and returns task, data, complete:true and partial. Missing pages, repeated cursors, duplicate records and unavailable results stop the export. The task retains billing, source outcomes, coverage and expiry metadata. Complete delivery does not mean exhaustive coverage of an upstream source.
The default recovery window is five minutes, with two seconds between polls. Each HTTP call has a 30-second timeout. Responses are limited to 8 MiB each and the assembled export to a 32 MiB serialized size by default; actual memory use can be larger. For larger delivery, use an appropriate download or streaming path instead of assuming model context can hold every record.
Keep result text separate from instructions
Job listings are untrusted data. The example’s system instruction marks them as such, but this is not proof of prompt-injection resistance. Use read-only tools for downstream text analysis when it does not need to start or cancel work.
Model requests and optional LangChain tracing may contain your prompt, tool inputs and returned records. Configure provider use, tracing and retention deliberately. The API key and request key remain outside tool schemas, and transport errors omit raw response details. Authentication, budget, pricing and result errors require handling; none should become a fabricated successful result.
Job Search API contract · Error reference · All integrations
The shared REST reader requires UTF-8 JSON and rejects nonfinite numbers, including numeric overflow. Interrupted or oversized HTTP error bodies keep a redacted HTTP-status diagnostic, and truncated successful transfers fail without returning data. It also rejects duplicate member names within an object, including names written with equivalent Unicode escapes; repeated names in separate records are allowed. Recovery also rejects nonfinite values from tool output instead of marking the export complete. Preserve the saved task ID and original request key after an error; these checks do not create or retry collection.
For each available result page, the reader checks the task again after receiving the page, including the final page. This adds one read-only task GET per page. Changed identity, status, availability or count, or a failed recheck, prevents a complete export. The check is a point-in-time observation; files can expire or become unavailable afterward.
Before collection, the creation tool checks that the estimate matches the requested input and that reserved billing units equal the record limit multiplied by the unit price. Amounts must be positive ASCII integers, and the reservation must fit the host credit budget. Invalid estimates stop before submission; server-side pricing and budget checks still apply.