@invokehq/sdk is the whole integration. It has one method that matters: invoke.call().
The contract. If
call() resolves, the action happened and you hold its receipt; a repeat of the same call returns that same receipt instead of acting again. If it didn’t happen, call() throws, and the error’s class tells you whether it happened.Install
Get a key
In the console, open API and copy the Agent key. It belongs to one agent, and every call made with it is recorded as that agent’s. The key proves the identity, so you can leave outagentId.
agentId on each call, or set INVOKE_AGENT_ID. Keep keys on the server. Never ship one to a browser.
Invoke.fromEnv() reads these. To configure in code instead, use new Invoke({ apiKey, baseUrl, workspaceId, agentId, timeoutMs, maxRetries, fetch }).
invoke.call()
Before the tool runs, Invoke checks the agent’s identity and permissions, your workspace policies, the budget, and whether another agent has claimed the work item. Then it reserves the cost, runs the tool once, settles the cost and seals a receipt.
The result
call() resolves only for an action that happened:
Idempotency
Name every action that must not happen twice. The sameidempotencyKey means the same action. It could be sent again by your retry loop, a worker that crashed and restarted, or an agent re-running its plan. Either way it runs once, and every repeat gets the original receipt with status: "duplicate".
Build the key from what makes the action unique, such as invoice:${invoiceId}, DRA-8:done or webhook:${event.id}. Reusing a key with different params is refused with idempotency_conflict, because one key names one action.
Without a key, the SDK makes one for each call, so its own network retries are still safe. But if your code calls again, that’s a new action.
Errors
Every failure is anInvokeError. Its class tells you whether the action happened:
When the outcome is unknown
Sometimes the request reaches the tool and the answer never comes back. Invoke doesn’t guess what happened.- Tools that are safe to re-run as the same action, such as reads and
linear.update_issue, are reconciled for you: the SDK sends the same action again. You only seeOutcomeUnknownErrorif that fails too. - Anything else, such as a charge or an email, could act twice if retried. Invoke holds the action as unknown and sets
err.safeToRetrytofalse. Someone checks the real system and settles it aterr.resolveUrl.happenedcommits the action and seals its receipt.not_happenedreleases the budget so an honest retry can run.
Approvals
Approvals come from workspace policies. For example, “stripe.charge_customer over 5000 needs a human” (created with an account key):
ApprovalRequiredError, and nothing runs. To wait for the decision instead, which by default waits up to 10 minutes:
call() resolves with its receipt, which records who approved it. If the reviewer rejects it, call() throws DeniedError.
Before and after
Next steps
- Quick Start: your first call in five minutes
- How It Works: what Invoke checks before an action runs
- Environment Variables: every setting the SDK reads