Web - Human in the loop

Free Webhook Action API Endpoint

Turn a JSON field definition into one hosted form or a group of separate bearer links. Read, wait for or receive a signal when the answers are ready.

  • No API key
  • 1 to 20 people
  • Wait up to 25s
  • 24-hour expiry

Create and read

POST/webhook_action

GET/webhook_action/{action_id}

https://aisenseapi.com/services/v1

Create an approval form

Describe the decision as JSON. Give it a title, an optional description and a list of fields.

curl -X POST https://aisenseapi.com/services/v1/webhook_action \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Approve invoice INV-2043?",
    "description": "Vendor total exceeds the auto-approval limit.",
    "fields": [
      {
        "type": "radio",
        "name": "decision",
        "label": "Decision",
        "required": true,
        "options": [
          {"value":"approve","label":"Approve"},
          {"value":"reject","label":"Reject"}
        ]
      },
      {"type":"textarea","name":"comment","label":"Notes","max_length":500}
    ]
  }'
{
  "ok": true,
  "action_id": "c2bcee60-016d-419e-a252-4e60600a2e2e",
  "form_url": "https://aisenseapi.com/services/v1/webhook_action/c2bcee60-016d-419e-a252-4e60600a2e2e/form",
  "result_url": "https://aisenseapi.com/services/v1/webhook_action/c2bcee60-016d-419e-a252-4e60600a2e2e",
  "wait_url": "https://aisenseapi.com/services/v1/webhook_action/c2bcee60-016d-419e-a252-4e60600a2e2e/wait/25",
  "expire_timestamp": 1787266368,
  "expire_datetime": "2026-08-20T22:52:48Z"
}

One call creates three things. The form_url is a real HTML page that opens in any browser. The result_url returns JSON for your workflow. The action_id appears inside both, so a single string is all you need to keep.

Nothing else is required. No key travels with the request, you host no receiver, and you open no inbound port.

Ask a group

Add "respondents": 3 to create three separate form links. The create response returns form_urls instead of form_url. Each link works once and stores only a hash of its bearer token.

{
  "title": "Choose the release window",
  "respondents": 3,
  "fields": [
    {"type":"radio","name":"decision","label":"Window","required":true,
     "options":["morning","evening"]}
  ]
}

The group result starts at pending, moves to partial after the first answer and becomes answered after all links are used. It reports respondents, answered, tally and responses. The tally counts the field named decision.

Read, wait or receive a signal

A plain GET returns immediately. Add /wait/25 to wait for up to 25 seconds. A group wait also returns as soon as one new answer changes the state.

curl https://aisenseapi.com/services/v1/webhook_action/c2bcee60-016d-419e-a252-4e60600a2e2e/wait/25
{
  "ok": true,
  "action_id": "c2bcee60-016d-419e-a252-4e60600a2e2e",
  "status": "pending",
  "created_at_timestamp": 1787179968,
  "created_at_datetime": "2026-08-19T22:52:48Z",
  "expire_timestamp": 1787266368,
  "expire_datetime": "2026-08-20T22:52:48Z",
  "answered_at_timestamp": null,
  "answered_at_datetime": null,
  "response": null
}

Until someone answers, status reads pending and response is null. A waiting response adds waited_seconds and wait_reason.

Now the reviewer opens the form and submits it. The same URL changes shape.

{
  "ok": true,
  "action_id": "c2bcee60-016d-419e-a252-4e60600a2e2e",
  "status": "answered",
  "created_at_timestamp": 1787179968,
  "created_at_datetime": "2026-08-19T22:52:48Z",
  "expire_timestamp": 1787266368,
  "expire_datetime": "2026-08-20T22:52:48Z",
  "answered_at_timestamp": 1787179994,
  "answered_at_datetime": "2026-08-19T22:53:14Z",
  "response": {
    "decision": "approve",
    "comment": "Budget confirmed by finance"
  }
}

Every answer sits under response, keyed by the name you gave that field when you created the action. Group actions return the same objects inside responses.

You may add notify_url to the create body. After the single answer, or after the final group answer, that public URL receives one signal with the action ID, result URL and answer counts. It does not receive the answers themselves.

Field types the free webhook action API endpoint accepts

Five types cover the decisions most pipelines hand to a person.

TypeBest forImportant properties
radioOne visible choice from a short listoptions, required
selectOne choice from a longer listoptions, required
textShort free-form answersmax_length, required
textareaComments, reasons and instructionsmax_length, required
checkboxConfirmation or several independent choicesoptions, required

Options take either of two shapes. Plain strings work when the stored value and the visible label are the same. Objects with separate value and label properties work when they differ, which keeps machine-readable codes out of the reviewer's view.

{
  "title": "Route the support ticket",
  "fields": [
    {"type":"select","name":"queue","label":"Queue","required":true,
     "options":["billing","technical","sales"]},
    {"type":"text","name":"owner","label":"Assign to","max_length":40},
    {"type":"checkbox","name":"flags","label":"Flags",
     "options":["urgent","needs_manager"]}
  ]
}

That body builds a routing form with a required queue, a free-text owner capped at forty characters, and two flags the reviewer can tick independently.

Response fields

A read returns the same core fields before and after an answer.

FieldTypeDescription
action_idstringThe UUID that identifies this action.
statusstringpending, partial for a group, or answered.
created_at_timestampintegerUnix time when the action was created.
expire_timestampintegerUnix time exactly 24 hours after creation.
answered_at_timestampintegerUnix time when the action became complete, or null.
responseobjectThe single submitted response, or null.
respondentsintegerRequired answer count for a group.
answeredintegerAnswers received for a group.
tallyobjectCounts for the group field named decision.
responsesarrayCompleted group responses without bearer tokens.

Errors and repeat submissions

An unknown action ID answers with HTTP 404. An expired action answers with HTTP 410.

{"error":"Action id unknown"}

A second submission on a form that already carries an answer is refused with HTTP 409.

{"error":"Action already answered"}

That refusal earns its place. Each action is a one-shot decision, so a reviewer who reloads the page cannot quietly overwrite a verdict your pipeline has already acted on. The free webhook action API endpoint keeps the first answer and rejects the rest.

How a pause for a human works

Three steps sit between an automated run and a human verdict.

  1. Describe the decision

    POST a title, an optional description and one or more fields. The reply carries the two URLs you need.

  2. Deliver the form URL

    Send it through email, chat, a ticket comment or whatever channel the reviewer already watches. They open a page and press submit. There is no login and no app to install.

  3. Poll until the status changes

    Resume the workflow when status flips to answered, and branch on the values inside response.

The hosted page is deliberately ordinary. It is a plain HTML form that posts back to its own address, and it carries no script tags at all. That keeps it usable in a locked-down corporate browser or on a phone, and it means a reviewer who has never seen your pipeline still knows what to do with it.

Where a human decision belongs

Teams reach for the free webhook action API endpoint whenever a rule cannot settle something safely on its own. Four patterns come up again and again.

Deployment gates

Require an explicit go or no-go before a production change continues.

Agent escalation

Let an AI agent ask a person when it reaches a risky or ambiguous step.

Content review

Collect approval, rejection and revision notes in one predictable shape.

Exception handling

Pause an automation when a transaction or document needs human judgment.

The pattern also pairs well with an inbound listener. Capture a third-party callback with the webhook capture API endpoint, inspect what arrived, then raise an action when the payload looks wrong.

Expiry, security and limits

Actions expire 24 hours after creation. Design the caller to handle an action that is never answered, rather than polling forever.

Both URLs are unguessable capability URLs. Anyone holding one can open the form or read the answer, so send them to the intended reviewer and to nobody else. Confidential material, long retention and account-based access control belong in a system built for those things.

Create bodies are limited to 64 KB. A title may be 200 characters, a description 5000 characters and a form 20 fields. One field may have 50 options. Group actions accept 1 to 20 respondents.

The base URL is https://aisenseapi.com/services/v1. No key and no account are required. Every service on the free public REST APIs hub shares one limit of 5000 requests per IP per 24 hours. Use the wait URL instead of a tight polling loop.

Neighbouring services fill the gaps. Park a large payload in the storage API endpoint and put only its id in the description. Shorten a long form link with the URL shortener API endpoint before pasting it into a chat message. Check a payload against a rule with the validation API endpoint first, and raise an action only for the cases that fail. Used that way, the free webhook action API endpoint becomes the one step in a pipeline where a person is genuinely required.