Quick start
Create an approval with your server-side API key. The human receives a single-use decision link; your application receives the result through a signed webhook.
appr_live_ key in a browser, model prompt, or public decision URL.curl https://api.nodsend.com/v1/approvals \
-X POST \
-H "Authorization: Bearer appr_live_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: deploy-prod-1042" \
-d '{
"action": "deploy_production",
"summary": "Release version 4.2 to production",
"channel": "email",
"recipient": "[email protected]",
"expires_in": "1h",
"external_id": "release-1042"
}'Create an approval
POST /v1/approvals is authenticated with an API key. Use an idempotency key whenever a network retry could otherwise create the same decision twice.
| Field | Type | Required | Description |
|---|---|---|---|
action | string | yes | Stable machine-readable action name. |
summary | string | yes | Plain-language decision summary. |
recipient | yes | Person authorized to decide. | |
channel | yes | Delivery channel. Email is currently supported. | |
expires_in | duration | no | Decision window such as 30m, 1h, or 1d. |
external_id | string | no | Your durable workflow identifier. |
metadata | object | no | Non-sensitive correlation data. |
webhook_id | string | no | A registered webhook destination. |
Verify every webhook
Compute HMAC-SHA256 over <event_id>.<timestamp>.<raw_body>, compare it in constant time, and reject timestamps outside your replay window.
Nodsend-Webhook-Id: evt_01J...
Nodsend-Webhook-Timestamp: 1786197600
Nodsend-Webhook-Signature: v1=8f7d...
{
"event_id": "evt_01J...",
"event_type": "approval.approved",
"created_at": "2026-08-08T12:00:00Z",
"data": {
"approval": {
"id": "apr_01J...",
"status": "approved",
"action": "deploy_production"
}
}
}LangChain and LangGraph
Bridge Nodsend to durable interrupts and resume the same thread only after the signed decision event arrives.
from nodsend.integrations.langchain import approval_kwargs_from_interrupt
approval = nodsend.approvals.create(
**approval_kwargs_from_interrupt(
interrupt,
recipient="[email protected]",
thread_id=thread_id,
webhook_id=webhook_id,
)
)CrewAI
Use Nodsend as an external feedback provider or guard selected consequential tool calls in a crew or flow.
from nodsend.integrations.crewai import NodsendFeedbackProvider
provider = NodsendFeedbackProvider(
nodsend,
recipient="[email protected]",
webhook_id=webhook_id,
)
# Pass provider to CrewAI's @human_feedback gate.AutoGen
Keep the sensitive side effect inside an approval-aware function tool so the model cannot bypass the decision boundary.
from nodsend.integrations.autogen import function_tool
guarded_deploy = function_tool(
deploy_production,
client=nodsend,
recipient="[email protected]",
summary="Deploy version 4.2 to production",
description="Deploy only after human approval",
)
assistant = AssistantAgent(tools=[guarded_deploy])Security model
Human decision tokens authorize one approval and are stored as hashes.
Only one terminal decision can win, even under concurrent requests.
Stable event IDs, timestamps, and HMAC signatures protect resumption.
Agent APIs scope every approval and webhook to the owning workspace.