# IVR HTTP Request Node: Call Your API From a Live Call

> How to call your own API from an IVR flow: sync vs async HTTP requests, tokens like {{digits}} and {{var.order_id}}, success codes, retries, timeouts, HMAC signature verification and HTTP logs.

Source: https://edesy.in/blog/ivr-http-request-node-call-your-api-2026

**The HTTP Request node lets an IVR call your API in the middle of a call. In async mode it fires in the
background with retries and the call carries on. In sync mode the caller waits up to 5 seconds and the flow
branches on Success or Failure. Every request is HTTPS, filled with call tokens, and HMAC-signed.**

> **Wire your API into a call flow:** [Try Edesy IVR Studio](https://ivr.edesy.in/?utm_source=edesy.in&utm_medium=blog&utm_campaign=ivr-http-request-node-call-your-api-2026) — Rs 20 free credit on sign-up, no card needed.

## What you can do with it

- Confirm or cancel an order when the caller presses 1 or 2.
- Record a survey rating and a spoken reason in your database.
- Check whether you're open, and branch to a team or to voicemail.
- Check whether a caller's number is a known customer, and branch to a priority line.
- Create a ticket or a lead in your CRM from a menu choice.

## Node settings

| Setting | Options / default | Notes |
|---|---|---|
| Method | GET, POST, PUT, PATCH, DELETE; default POST | |
| URL | https only | Tokens allowed in path and query, not in the host |
| Headers | key/value rows | Token values allowed; `x-edesy-*`, Host and Content-Length are reserved |
| Content type | JSON, form-urlencoded, text; default JSON | |
| Body | template | In JSON, put tokens inside string values; they're escaped safely |
| Mode | async (default) or sync | |
| Timeout | sync 500 to 5,000 ms; async 1,000 to 10,000 ms per attempt; default 3,000 | |
| Max attempts (async) | 1 to 5, default 3 | Retries network errors, 5xx, 408, 429 with backoff |
| Success codes (sync) | default `2xx`, or a list like `200,201,409` | Anything else is Failure |

## Tokens you can use

| Token | Value |
|---|---|
| `{{caller}}` | Caller's number |
| `{{did}}` | Your number that was called |
| `{{digits}}` | Raw keys pressed at the last menu |
| `{{menu_choice}}` | The menu option's name, such as "Support" |
| `{{answer.<key>}}` | A spoken answer from an Ask node |
| `{{var.<name>}}` | A variable passed to the outbound IVR API |
| `{{call_sid}}`, `{{flow_id}}`, `{{reference_id}}` | Identifiers for matching on your side |
| `{{time}}`, `{{time_iso}}` | Time in IST (readable) and ISO 8601 UTC |
| `{{voicemail_url}}` | Voicemail link, when one exists on the call |

## Sync or async?

Use **async** when the caller doesn't need to wait for the answer: logging a rating, notifying your CRM,
recording a lead. It's resilient: if your API is briefly down, the request is retried after the call moves on.

Use **sync** when the next step depends on your system: "is this order still cancellable?", "are we open?".
Keep sync endpoints fast. The caller hears silence while waiting, so budget well under the 5-second cap, and
always connect the **Failure** branch to something sensible, such as "Sorry, we couldn't do that right now.
Connecting you to our team."

## Example: confirm an order on keypress

Flow (the "Order confirmation (API + HTTP)" template):

1. Your app places the call: `POST /v1/ivr/calls` with the flow ID and `variables` such as
   `order_id` and `customer_name`, plus an idempotency key.
2. **Say:** "Hello {{var.customer_name}}, about your order {{var.order_id}}..."
3. **Menu:** 1 to confirm, 2 to cancel.
4. **HTTP Request** (sync, POST) on branch 1:

```
URL:  https://api.example.com/orders/{{var.order_id}}/confirm
Body: {
  "order_id": "{{var.order_id}}",
  "digit": "{{digits}}",
  "caller": "{{caller}}",
  "call_sid": "{{call_sid}}"
}
```

5. **Success:** "Thank you, your order is confirmed." **Failure:** transfer to your team.

Your endpoint should be **idempotent**: treat a repeat with the same `call_sid` as a no-op, because async
retries and a caller pressing twice can both send the same request.

## Example: are we open?

Put a sync GET first in the flow:

```
GET https://api.example.com/ivr/open?did={{did}}
```

Return 200 when you're open and 503 when you're closed. Success goes to your menu; Failure goes to an
after-hours message and voicemail. IVR Studio has no built-in business-hours switch, so this keeps the
schedule (and holidays) in your own system. See
[voicemail for after-hours calls](https://edesy.in/blog/voicemail-to-email-ivr-after-hours-2026).

## Verifying the signature

Every request carries two headers:

- `X-Edesy-Timestamp`: Unix seconds.
- `X-Edesy-Signature`: `sha256=` + hex(HMAC-SHA256(secret, timestamp + "." + raw_body)).

Your signing secret is in the IVR portal and can be rotated. In Node.js:

```js
import crypto from "node:crypto";

function verify(req, rawBody, secret) {
  const ts = req.headers["x-edesy-timestamp"];
  const sig = req.headers["x-edesy-signature"] || "";
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = "sha256=" +
    crypto.createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
  return sig.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
```

Hash the **raw** body bytes, not re-serialised JSON, and reject timestamps older than a few minutes.

## Debugging

- **HTTP logs** in the portal show each request, response code, a truncated response body, duration and
  retries. The same data is available from `/v1/ivr/http-logs`.
- **Test before publishing** with the HTTP test endpoint (`/v1/ivr/http-test`) or a test call from the
  builder.
- **Live validation** warns when a sync node has no Success or Failure branch connected (the call would
  hang up there) and blocks branches on an async node.

## Common mistakes

- Putting a token in the host name (not allowed; keep the host fixed).
- Sync calls to slow endpoints, leaving callers in silence.
- No Failure branch, or a Failure branch that hangs up without explanation.
- Non-idempotent handlers that confirm the same order twice.
- Verifying the signature against parsed-and-re-stringified JSON.

## Cost

You pay for call minutes: IVR Studio is Rs 1.50/min plus number rental, excluding 18% GST. More detail in the [outbound IVR API guide](https://edesy.in/blog/ivr-outbound-call-api-guide-2026),
on the [HTTP Request node page](https://edesy.in/ivr/features/http-request-node) and in the [IVR docs](https://edesy.in/docs/ivr).

[Build a flow that calls your API](https://ivr.edesy.in/?utm_source=edesy.in&utm_medium=blog&utm_campaign=ivr-http-request-node-call-your-api-2026)
with Rs 20 free credit, no card needed.

## Frequently Asked Questions

### What does the HTTP Request node do?

It sends an HTTPS request from your IVR flow to your own API while the call is live. You choose the method, URL, headers and body, and fill them with call data such as the caller's number, the key pressed, spoken answers and variables passed to the call.

### What is the difference between sync and async mode?

Async (the default) sends the request in the background, retries on failure, and the call continues immediately. Sync makes the caller wait for the response, up to 5 seconds, and the flow branches on Success or Failure.

### What counts as success in sync mode?

A response status in your success codes, which default to 2xx. You can list specific codes such as 200,201,409. Any other status, a timeout or a network error takes the Failure branch.

### Can the IVR read a value from my API's response?

No. The flow branches on the status code only; the response body is stored, truncated, in the HTTP logs for debugging. If the next prompt depends on your data, pass it as variables when you place the call with the outbound IVR API, or encode the decision in the status code.

### How do I verify a request came from Edesy?

Each request carries X-Edesy-Timestamp and X-Edesy-Signature headers. The signature is sha256= followed by the hex HMAC-SHA256 of the timestamp, a dot, and the raw body, using your IVR signing secret. Compute it on your side, compare in constant time, and reject old timestamps.

### What is retried in async mode?

Network errors, 5xx responses, 408 and 429 are retried with backoff, up to the max attempts you set (1 to 5, default 3). Each attempt has its own timeout of 1 to 10 seconds.
